Version 2.6.0-dev.8.0

Merge commit 'b28b9ae8fc1bf755c450a35b72137a9f40d2c2' into dev
diff --git a/.packages b/.packages
index dc5f1ef..5590179 100644
--- a/.packages
+++ b/.packages
@@ -37,6 +37,7 @@
 dev_compiler:pkg/dev_compiler/lib
 diagnostic:pkg/diagnostic/lib
 expect:pkg/expect/lib
+ffi:third_party/pkg/ffi/lib
 fixnum:third_party/pkg/fixnum/lib
 frontend_server:pkg/frontend_server/lib
 front_end:pkg/front_end/lib
diff --git a/AUTHORS b/AUTHORS
index c61ecfc..b3a3ac6 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -5,6 +5,7 @@
 
 Google Inc.
 The V8 project authors
+Arm Ltd. <*@arm.com>
 
 Ola Martin Bini <ola.bini@gmail.com>
 Michael Haubenwallner <michael.haubenwallner@gmail.com>
diff --git a/BUILD.gn b/BUILD.gn
index 6a6034d..bafc121 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -3,15 +3,10 @@
 # BSD-style license that can be found in the LICENSE file.
 
 import("build/config/gclient_args.gni")
+import("sdk_args.gni")
 
 targetting_fuchsia = target_os == "fuchsia"
 
-declare_args() {
-  # Whether to use the NNBD fork of the SDK core libraries.
-  # TODO(rnystrom): Remove this when the fork has been merged back in.
-  use_nnbd = false
-}
-
 # This target will be built if no target is specified when invoking ninja.
 group("default") {
   if (targetting_fuchsia) {
@@ -121,6 +116,12 @@
   ]
 }
 
+group("dartfix") {
+  deps = [
+    "utils/dartfix",
+  ]
+}
+
 group("analysis_server") {
   deps = [
     "utils/analysis_server",
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0280d0b..6ee98ea 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -77,11 +77,14 @@
 
 #### `dart:developer`
 
-* Added optional `parent` paremeter to `TimelineTask` constructors to allow for
+* Added optional `parent` parameter to `TimelineTask` constructor to allow for
   linking of asynchronous timeline events in the DevTools timeline view.
 
 ### Dart VM
 
+* Added a new tool for AOT compiling Dart programs to native, self-contained
+executables. See https://dart.dev/tools/dart2native for additional details.
+
 ### Dart for the Web
 
 #### Dart Dev Compiler (DDC)
@@ -95,10 +98,14 @@
 
 #### Linter
 
-The Linter was updated to `0.1.100`, which includes:
+The Linter was updated to `0.1.101`, which includes:
 
-* (internal) stop accessing `staticType` in favor of getting type of `FormalParameter`s from the declared element
-* (internal) remove stale analyzer work-around for collecting `TypeParameterElement`s in `prefer_const_constructors`
+* fixed `diagnostic_describe_all_properties` to flag properties in `Diagnosticable`s with no debug methods defined
+* fixed `noSuchMethod` exception in `camel_case_extensions` when analyzing unnamed extensions
+* fixed `avoid_print` to catch tear-off usage
+* new lint: `avoid_web_libraries_in_flutter` (experimental)
+* (internal) prepare `unnecessary_lambdas` for coming `MethodInvocation` vs. `FunctionExpressionInvocation` changes
+
 
 ## 2.5.1 - 2019-09-27
 
diff --git a/DEPS b/DEPS
index be3f1d9..8dc6a83 100644
--- a/DEPS
+++ b/DEPS
@@ -38,7 +38,7 @@
 
   # co19 is a cipd package. Use tests/co19_2/update.sh to update this hash.
   # It requires access to the dart-build-access group, which EngProd has.
-  "co19_2_rev": "52daae49d7bff80039ff1eea36a24e98c2b9a837",
+  "co19_2_rev": "a8f7aa15ab860a309667168243bda01fda0794df",
 
   # As Flutter does, we use Fuchsia's GN and Clang toolchain. These revision
   # should be kept up to date with the revisions pulled by the Flutter engine.
@@ -84,7 +84,9 @@
   # For more details, see https://github.com/dart-lang/sdk/issues/30164
   "dart_style_tag": "1.3.1",  # Please see the note above before updating.
 
-  "dartdoc_tag" : "v0.28.7",
+  "args_tag" : "1.5.2",
+  "dartdoc_tag" : "v0.28.8",
+  "ffi_tag": "ea88d71b043ee14b268c3aedff14e9eb32e20959",
   "fixnum_tag": "0.10.9",
   "glob_tag": "1.1.7",
   "html_tag" : "0.14.0+1",
@@ -99,7 +101,7 @@
   "intl_tag": "0.15.7",
   "jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
   "json_rpc_2_tag": "2.0.9",
-  "linter_tag": "0.1.100",
+  "linter_tag": "0.1.101",
   "logging_tag": "0.11.3+2",
   "markupsafe_rev": "8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
   "markdown_tag": "2.1.1",
@@ -138,7 +140,7 @@
   "term_glyph_tag": "1.0.1",
   "test_reflective_loader_tag": "0.1.9",
   "test_tag": "test-v1.6.4",
-  "tflite_native_rev": "06e533a9747306d1114c53427cc67eda080f51f9",
+  "tflite_native_rev": "3c777c40608a2a9f1427bfe0028ab48e7116b4c1",
   "typed_data_tag": "1.1.6",
   "unittest_rev": "2b8375bc98bb9dc81c539c91aaea6adce12e1072",
   "usage_tag": "3.4.0",
@@ -275,8 +277,12 @@
       Var("dart_git") + "dart_style.git" + "@" + Var("dart_style_tag"),
   Var("dart_root") + "/third_party/pkg/dart2js_info":
       Var("dart_git") + "dart2js_info.git" + "@" + Var("dart2js_info_tag"),
+  Var("dart_root") + "/third_party/pkg/args":
+      Var("dart_git") + "args.git" + "@" + Var("args_tag"),
   Var("dart_root") + "/third_party/pkg/dartdoc":
       Var("dart_git") + "dartdoc.git" + "@" + Var("dartdoc_tag"),
+  Var("dart_root") + "/third_party/pkg/ffi":
+      Var("dart_git") + "ffi.git" + "@" + Var("ffi_tag"),
   Var("dart_root") + "/third_party/pkg/fixnum":
       Var("dart_git") + "fixnum.git" + "@" + Var("fixnum_tag"),
   Var("dart_root") + "/third_party/pkg/glob":
@@ -421,7 +427,7 @@
     "packages": [
       {
         "package": "dart/language_model",
-        "version": "EFtZ0Z5T822s4EUOOaWeiXUppRGKp5d9Z6jomJIeQYcC",
+        "version": "9fJQZ0TrnAGQKrEtuL3-AXbUfPzYxqpN_OBHr9P4hE4C",
       }
     ],
     "dep_type": "cipd",
diff --git a/benchmarks/FfiBoringssl/dart/FfiBoringssl.dart b/benchmarks/FfiBoringssl/dart/FfiBoringssl.dart
index c87711b..c377b7f 100644
--- a/benchmarks/FfiBoringssl/dart/FfiBoringssl.dart
+++ b/benchmarks/FfiBoringssl/dart/FfiBoringssl.dart
@@ -9,6 +9,7 @@
 import 'dart:typed_data';
 
 import 'package:benchmark_harness/benchmark_harness.dart';
+import 'package:ffi/ffi.dart';
 
 import 'digest.dart';
 import 'types.dart';
@@ -29,7 +30,7 @@
   final result = Uint8List(length);
   final uint8bytes = bytes.asUint8Pointer();
   for (int i = 0; i < length; i++) {
-    result[i] = uint8bytes.elementAt(i).load<int>();
+    result[i] = uint8bytes[i];
   }
   return result;
 }
@@ -38,7 +39,7 @@
   final int length = source.length;
   final uint8target = target.asUint8Pointer();
   for (int i = 0; i < length; i++) {
-    uint8target.offsetBy(i).store(source[i]);
+    uint8target[i] = source[i];
   }
 }
 
@@ -47,12 +48,11 @@
   EVP_DigestInit(context, hashAlgorithm);
   EVP_DigestUpdate(context, data, length);
   final int resultSize = EVP_MD_CTX_size(context);
-  final Pointer<Bytes> result =
-      Pointer<Uint8>.allocate(count: resultSize).cast();
-  EVP_DigestFinal(context, result, nullptr.cast());
+  final Pointer<Bytes> result = allocate<Uint8>(count: resultSize).cast();
+  EVP_DigestFinal(context, result, nullptr);
   EVP_MD_CTX_free(context);
-  final String hash = base64Encode(toUint8List(result.load(), resultSize));
-  result.free();
+  final String hash = base64Encode(toUint8List(result.ref, resultSize));
+  free(result);
   return hash;
 }
 
@@ -85,13 +85,13 @@
   Pointer<Data> data; // Data in C memory that we want to digest.
 
   void setup() {
-    data = Pointer<Uint8>.allocate(count: L).cast();
-    copyFromUint8ListToTarget(inventData(L), data.load());
+    data = allocate<Uint8>(count: L).cast();
+    copyFromUint8ListToTarget(inventData(L), data.ref);
     hash(data, L, hashAlgorithm);
   }
 
   void teardown() {
-    data.free();
+    free(data);
   }
 
   void run() {
@@ -112,19 +112,19 @@
 
   void setup() {
     data = inventData(L);
-    final Pointer<Data> dataInC = Pointer<Uint8>.allocate(count: L).cast();
-    copyFromUint8ListToTarget(data, dataInC.load());
+    final Pointer<Data> dataInC = allocate<Uint8>(count: L).cast();
+    copyFromUint8ListToTarget(data, dataInC.ref);
     hash(dataInC, L, hashAlgorithm);
-    dataInC.free();
+    free(dataInC);
   }
 
   void teardown() {}
 
   void run() {
-    final Pointer<Data> dataInC = Pointer<Uint8>.allocate(count: L).cast();
-    copyFromUint8ListToTarget(data, dataInC.load());
+    final Pointer<Data> dataInC = allocate<Uint8>(count: L).cast();
+    copyFromUint8ListToTarget(data, dataInC.ref);
     final String result = hash(dataInC, L, hashAlgorithm);
-    dataInC.free();
+    free(dataInC);
     if (result != expectedHash) {
       throw Exception("$name: Unexpected result: $result");
     }
diff --git a/benchmarks/FfiBoringssl/dart/types.dart b/benchmarks/FfiBoringssl/dart/types.dart
index c36c851..5d97475 100644
--- a/benchmarks/FfiBoringssl/dart/types.dart
+++ b/benchmarks/FfiBoringssl/dart/types.dart
@@ -5,21 +5,21 @@
 import 'dart:ffi';
 
 /// digest algorithm.
-class EVP_MD extends Struct<EVP_MD> {}
+class EVP_MD extends Struct {}
 
 /// digest context.
-class EVP_MD_CTX extends Struct<EVP_MD_CTX> {}
+class EVP_MD_CTX extends Struct {}
 
 /// Type for `void*` used to represent opaque data.
-class Data extends Struct<Data> {
-  static Data fromUint8Pointer(Pointer<Uint8> p) => p.cast<Data>().load();
+class Data extends Struct {
+  static Data fromUint8Pointer(Pointer<Uint8> p) => p.cast<Data>().ref;
 
   Pointer<Uint8> asUint8Pointer() => this.addressOf.cast();
 }
 
 /// Type for `uint8_t*` used to represent byte data.
-class Bytes extends Struct<Bytes> {
-  static Data fromUint8Pointer(Pointer<Uint8> p) => p.cast<Data>().load();
+class Bytes extends Struct {
+  static Data fromUint8Pointer(Pointer<Uint8> p) => p.cast<Data>().ref;
 
   Pointer<Uint8> asUint8Pointer() => this.addressOf.cast();
 }
diff --git a/benchmarks/FfiCall/dart/FfiCall.dart b/benchmarks/FfiCall/dart/FfiCall.dart
index d7e31c4..68d6601 100644
--- a/benchmarks/FfiCall/dart/FfiCall.dart
+++ b/benchmarks/FfiCall/dart/FfiCall.dart
@@ -10,6 +10,7 @@
 import 'dart:ffi';
 import 'dart:io';
 
+import 'package:ffi/ffi.dart';
 import 'package:benchmark_harness/benchmark_harness.dart';
 
 import 'dlopen_helper.dart';
@@ -919,8 +920,8 @@
   PointerUint8x01() : super("FfiCall.PointerUint8x01");
 
   Pointer<Uint8> pointer;
-  void setup() => pointer = Pointer.allocate(count: N + 1);
-  void teardown() => pointer.free();
+  void setup() => pointer = allocate(count: N + 1);
+  void teardown() => free(pointer);
 
   void run() {
     final Pointer<Uint8> x = doCall1PointerUint8(N, pointer);
@@ -936,12 +937,12 @@
   Pointer<Uint8> pointer, pointer2;
 
   void setup() {
-    pointer = Pointer.allocate(count: N + 1);
+    pointer = allocate(count: N + 1);
     pointer2 = pointer.elementAt(1);
   }
 
   void teardown() {
-    pointer.free();
+    free(pointer);
   }
 
   void run() {
@@ -958,14 +959,14 @@
   Pointer<Uint8> pointer, pointer2, pointer3, pointer4;
 
   void setup() {
-    pointer = Pointer.allocate(count: N + 1);
+    pointer = allocate(count: N + 1);
     pointer2 = pointer.elementAt(1);
     pointer3 = pointer.elementAt(2);
     pointer4 = pointer.elementAt(3);
   }
 
   void teardown() {
-    pointer.free();
+    free(pointer);
   }
 
   void run() {
@@ -992,7 +993,7 @@
       pointer10;
 
   void setup() {
-    pointer = Pointer.allocate(count: N + 1);
+    pointer = allocate(count: N + 1);
     pointer2 = pointer.elementAt(1);
     pointer3 = pointer.elementAt(2);
     pointer4 = pointer.elementAt(3);
@@ -1005,7 +1006,7 @@
   }
 
   void teardown() {
-    pointer.free();
+    free(pointer);
   }
 
   void run() {
@@ -1052,7 +1053,7 @@
       pointer20;
 
   void setup() {
-    pointer = Pointer.allocate(count: N + 1);
+    pointer = allocate(count: N + 1);
     pointer2 = pointer.elementAt(1);
     pointer3 = pointer.elementAt(2);
     pointer4 = pointer.elementAt(3);
@@ -1075,7 +1076,7 @@
   }
 
   void teardown() {
-    pointer.free();
+    free(pointer);
   }
 
   void run() {
diff --git a/benchmarks/FfiMemory/dart/FfiMemory.dart b/benchmarks/FfiMemory/dart/FfiMemory.dart
index 39c053f..9bfad25 100644
--- a/benchmarks/FfiMemory/dart/FfiMemory.dart
+++ b/benchmarks/FfiMemory/dart/FfiMemory.dart
@@ -11,6 +11,7 @@
 
 import 'dart:ffi';
 
+import 'package:ffi/ffi.dart';
 import 'package:benchmark_harness/benchmark_harness.dart';
 
 //
@@ -19,74 +20,74 @@
 
 void doStoreInt8(Pointer<Int8> pointer, int length) {
   for (int i = 0; i < length; i++) {
-    pointer.elementAt(i).store(1);
+    pointer[i] = 1;
   }
 }
 
 void doStoreUint8(Pointer<Uint8> pointer, int length) {
   for (int i = 0; i < length; i++) {
-    pointer.elementAt(i).store(1);
+    pointer[i] = 1;
   }
 }
 
 void doStoreInt16(Pointer<Int16> pointer, int length) {
   for (int i = 0; i < length; i++) {
-    pointer.elementAt(i).store(1);
+    pointer[i] = 1;
   }
 }
 
 void doStoreUint16(Pointer<Uint16> pointer, int length) {
   for (int i = 0; i < length; i++) {
-    pointer.elementAt(i).store(1);
+    pointer[i] = 1;
   }
 }
 
 void doStoreInt32(Pointer<Int32> pointer, int length) {
   for (int i = 0; i < length; i++) {
-    pointer.elementAt(i).store(1);
+    pointer[i] = 1;
   }
 }
 
 void doStoreUint32(Pointer<Uint32> pointer, int length) {
   for (int i = 0; i < length; i++) {
-    pointer.elementAt(i).store(1);
+    pointer[i] = 1;
   }
 }
 
 void doStoreInt64(Pointer<Int64> pointer, int length) {
   for (int i = 0; i < length; i++) {
-    pointer.elementAt(i).store(1);
+    pointer[i] = 1;
   }
 }
 
 void doStoreUint64(Pointer<Uint64> pointer, int length) {
   for (int i = 0; i < length; i++) {
-    pointer.elementAt(i).store(1);
+    pointer[i] = 1;
   }
 }
 
 void doStoreFloat(Pointer<Float> pointer, int length) {
   for (int i = 0; i < length; i++) {
-    pointer.elementAt(i).store(1.0);
+    pointer[i] = 1.0;
   }
 }
 
 void doStoreDouble(Pointer<Double> pointer, int length) {
   for (int i = 0; i < length; i++) {
-    pointer.elementAt(i).store(1.0);
+    pointer[i] = 1.0;
   }
 }
 
 void doStorePointer(
     Pointer<Pointer<Int8>> pointer, int length, Pointer<Int8> data) {
   for (int i = 0; i < length; i++) {
-    pointer.elementAt(i).store(data);
+    pointer[i] = data;
   }
 }
 
 void doStoreInt64Mint(Pointer<Int64> pointer, int length) {
   for (int i = 0; i < length; i++) {
-    pointer.elementAt(i).store(0x7FFFFFFFFFFFFFFF);
+    pointer[i] = 0x7FFFFFFFFFFFFFFF;
   }
 }
 
@@ -97,7 +98,7 @@
 int doLoadInt8(Pointer<Int8> pointer, int length) {
   int x = 0;
   for (int i = 0; i < length; i++) {
-    x += pointer.elementAt(i).load<int>();
+    x += pointer[i];
   }
   return x;
 }
@@ -105,7 +106,7 @@
 int doLoadUint8(Pointer<Uint8> pointer, int length) {
   int x = 0;
   for (int i = 0; i < length; i++) {
-    x += pointer.elementAt(i).load<int>();
+    x += pointer[i];
   }
   return x;
 }
@@ -113,7 +114,7 @@
 int doLoadInt16(Pointer<Int16> pointer, int length) {
   int x = 0;
   for (int i = 0; i < length; i++) {
-    x += pointer.elementAt(i).load<int>();
+    x += pointer[i];
   }
   return x;
 }
@@ -121,7 +122,7 @@
 int doLoadUint16(Pointer<Uint16> pointer, int length) {
   int x = 0;
   for (int i = 0; i < length; i++) {
-    x += pointer.elementAt(i).load<int>();
+    x += pointer[i];
   }
   return x;
 }
@@ -129,7 +130,7 @@
 int doLoadInt32(Pointer<Int32> pointer, int length) {
   int x = 0;
   for (int i = 0; i < length; i++) {
-    x += pointer.elementAt(i).load<int>();
+    x += pointer[i];
   }
   return x;
 }
@@ -137,7 +138,7 @@
 int doLoadUint32(Pointer<Uint32> pointer, int length) {
   int x = 0;
   for (int i = 0; i < length; i++) {
-    x += pointer.elementAt(i).load<int>();
+    x += pointer[i];
   }
   return x;
 }
@@ -145,7 +146,7 @@
 int doLoadInt64(Pointer<Int64> pointer, int length) {
   int x = 0;
   for (int i = 0; i < length; i++) {
-    x += pointer.elementAt(i).load<int>();
+    x += pointer[i];
   }
   return x;
 }
@@ -153,7 +154,7 @@
 int doLoadUint64(Pointer<Uint64> pointer, int length) {
   int x = 0;
   for (int i = 0; i < length; i++) {
-    x += pointer.elementAt(i).load<int>();
+    x += pointer[i];
   }
   return x;
 }
@@ -161,7 +162,7 @@
 double doLoadFloat(Pointer<Float> pointer, int length) {
   double x = 0;
   for (int i = 0; i < length; i++) {
-    x += pointer.elementAt(i).load<double>();
+    x += pointer[i];
   }
   return x;
 }
@@ -169,7 +170,7 @@
 double doLoadDouble(Pointer<Double> pointer, int length) {
   double x = 0;
   for (int i = 0; i < length; i++) {
-    x += pointer.elementAt(i).load<double>();
+    x += pointer[i];
   }
   return x;
 }
@@ -179,7 +180,7 @@
   Pointer<Int8> x;
   int address_xor = 0;
   for (int i = 0; i < length; i++) {
-    x = pointer.elementAt(i).load();
+    x = pointer[i];
     address_xor ^= x.address;
   }
   return address_xor;
@@ -188,7 +189,7 @@
 int doLoadInt64Mint(Pointer<Int64> pointer, int length) {
   int x = 0;
   for (int i = 0; i < length; i++) {
-    x += pointer.elementAt(i).load<int>();
+    x += pointer[i];
   }
   return x;
 }
@@ -211,8 +212,8 @@
   Pointer<Int8> pointer;
   PointerInt8() : super("FfiMemory.PointerInt8");
 
-  void setup() => pointer = Pointer.allocate(count: N);
-  void teardown() => pointer.free();
+  void setup() => pointer = allocate(count: N);
+  void teardown() => free(pointer);
 
   void run() {
     doStoreInt8(pointer, N);
@@ -227,8 +228,8 @@
   Pointer<Uint8> pointer;
   PointerUint8() : super("FfiMemory.PointerUint8");
 
-  void setup() => pointer = Pointer.allocate(count: N);
-  void teardown() => pointer.free();
+  void setup() => pointer = allocate(count: N);
+  void teardown() => free(pointer);
 
   void run() {
     doStoreUint8(pointer, N);
@@ -243,8 +244,8 @@
   Pointer<Int16> pointer;
   PointerInt16() : super("FfiMemory.PointerInt16");
 
-  void setup() => pointer = Pointer.allocate(count: N);
-  void teardown() => pointer.free();
+  void setup() => pointer = allocate(count: N);
+  void teardown() => free(pointer);
 
   void run() {
     doStoreInt16(pointer, N);
@@ -259,8 +260,8 @@
   Pointer<Uint16> pointer;
   PointerUint16() : super("FfiMemory.PointerUint16");
 
-  void setup() => pointer = Pointer.allocate(count: N);
-  void teardown() => pointer.free();
+  void setup() => pointer = allocate(count: N);
+  void teardown() => free(pointer);
 
   void run() {
     doStoreUint16(pointer, N);
@@ -275,8 +276,8 @@
   Pointer<Int32> pointer;
   PointerInt32() : super("FfiMemory.PointerInt32");
 
-  void setup() => pointer = Pointer.allocate(count: N);
-  void teardown() => pointer.free();
+  void setup() => pointer = allocate(count: N);
+  void teardown() => free(pointer);
 
   void run() {
     doStoreInt32(pointer, N);
@@ -291,8 +292,8 @@
   Pointer<Uint32> pointer;
   PointerUint32() : super("FfiMemory.PointerUint32");
 
-  void setup() => pointer = Pointer.allocate(count: N);
-  void teardown() => pointer.free();
+  void setup() => pointer = allocate(count: N);
+  void teardown() => free(pointer);
 
   void run() {
     doStoreUint32(pointer, N);
@@ -307,8 +308,8 @@
   Pointer<Int64> pointer;
   PointerInt64() : super("FfiMemory.PointerInt64");
 
-  void setup() => pointer = Pointer.allocate(count: N);
-  void teardown() => pointer.free();
+  void setup() => pointer = allocate(count: N);
+  void teardown() => free(pointer);
 
   void run() {
     doStoreInt64(pointer, N);
@@ -323,8 +324,8 @@
   Pointer<Uint64> pointer;
   PointerUint64() : super("FfiMemory.PointerUint64");
 
-  void setup() => pointer = Pointer.allocate(count: N);
-  void teardown() => pointer.free();
+  void setup() => pointer = allocate(count: N);
+  void teardown() => free(pointer);
 
   void run() {
     doStoreUint64(pointer, N);
@@ -339,8 +340,8 @@
   Pointer<Float> pointer;
   PointerFloat() : super("FfiMemory.PointerFloat");
 
-  void setup() => pointer = Pointer.allocate(count: N);
-  void teardown() => pointer.free();
+  void setup() => pointer = allocate(count: N);
+  void teardown() => free(pointer);
 
   void run() {
     doStoreFloat(pointer, N);
@@ -355,8 +356,8 @@
   Pointer<Double> pointer;
   PointerDouble() : super("FfiMemory.PointerDouble");
 
-  void setup() => pointer = Pointer.allocate(count: N);
-  void teardown() => pointer.free();
+  void setup() => pointer = allocate(count: N);
+  void teardown() => free(pointer);
 
   void run() {
     doStoreDouble(pointer, N);
@@ -373,13 +374,13 @@
   PointerPointer() : super("FfiMemory.PointerPointer");
 
   void setup() {
-    pointer = Pointer.allocate(count: N);
-    data = Pointer.allocate();
+    pointer = allocate(count: N);
+    data = allocate();
   }
 
   void teardown() {
-    pointer.free();
-    data.free();
+    free(pointer);
+    free(data);
   }
 
   void run() {
@@ -395,8 +396,8 @@
   Pointer<Int64> pointer;
   PointerInt64Mint() : super("FfiMemory.PointerInt64Mint");
 
-  void setup() => pointer = Pointer.allocate(count: N);
-  void teardown() => pointer.free();
+  void setup() => pointer = allocate(count: N);
+  void teardown() => free(pointer);
 
   void run() {
     doStoreInt64Mint(pointer, N);
diff --git a/benchmarks/FfiStruct/dart/FfiStruct.dart b/benchmarks/FfiStruct/dart/FfiStruct.dart
index ede799b..f2952ec 100644
--- a/benchmarks/FfiStruct/dart/FfiStruct.dart
+++ b/benchmarks/FfiStruct/dart/FfiStruct.dart
@@ -9,6 +9,7 @@
 
 import 'dart:ffi';
 
+import 'package:ffi/ffi.dart';
 import 'package:benchmark_harness/benchmark_harness.dart';
 
 //
@@ -17,7 +18,7 @@
 
 void doStoreInt32(Pointer<VeryLargeStruct> pointer, int length) {
   for (int i = 0; i < length; i++) {
-    pointer.elementAt(i).load<VeryLargeStruct>().c = 1;
+    pointer[i].c = 1;
   }
 }
 
@@ -28,7 +29,7 @@
 int doLoadInt32(Pointer<VeryLargeStruct> pointer, int length) {
   int x = 0;
   for (int i = 0; i < length; i++) {
-    x += pointer.elementAt(i).load<VeryLargeStruct>().c;
+    x += pointer[i].c;
   }
   return x;
 }
@@ -48,8 +49,8 @@
   Pointer<VeryLargeStruct> pointer;
   FieldLoadStore() : super("FfiStruct.FieldLoadStore");
 
-  void setup() => pointer = Pointer.allocate(count: N);
-  void teardown() => pointer.free();
+  void setup() => pointer = allocate(count: N);
+  void teardown() => free(pointer);
 
   void run() {
     doStoreInt32(pointer, N);
@@ -74,7 +75,7 @@
 //
 // Test struct.
 //
-class VeryLargeStruct extends Struct<VeryLargeStruct> {
+class VeryLargeStruct extends Struct {
   @Int8()
   int a;
 
diff --git a/benchmarks/IsolateSpawn/dart/IsolateSpawn.dart b/benchmarks/IsolateSpawn/dart/IsolateSpawn.dart
new file mode 100644
index 0000000..070edd0
--- /dev/null
+++ b/benchmarks/IsolateSpawn/dart/IsolateSpawn.dart
@@ -0,0 +1,182 @@
+// 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:isolate';
+import 'dart:math';
+
+import 'package:meta/meta.dart';
+
+import 'package:compiler/src/dart2js.dart' as dart2js_main;
+
+class SpawnLatencyAndMemory {
+  SpawnLatencyAndMemory(this.name);
+
+  Future<ResultMessageLatencyAndMemory> run() async {
+    final completerResult = Completer();
+    final receivePort = ReceivePort()..listen(completerResult.complete);
+    final Completer<DateTime> isolateExitedCompleter = Completer<DateTime>();
+    final onExitReceivePort = ReceivePort()
+      ..listen((_) {
+        isolateExitedCompleter.complete(DateTime.now());
+      });
+    final DateTime beforeSpawn = DateTime.now();
+    await Isolate.spawn(
+        isolateCompiler,
+        StartMessageLatencyAndMemory(
+            receivePort.sendPort, beforeSpawn, ProcessInfo.currentRss),
+        onExit: onExitReceivePort.sendPort,
+        onError: onExitReceivePort.sendPort);
+    final DateTime afterSpawn = DateTime.now();
+
+    final ResultMessageLatencyAndMemory result = await completerResult.future;
+    receivePort.close();
+    final DateTime isolateExited = await isolateExitedCompleter.future;
+    result.timeToExitUs = isolateExited.difference(beforeSpawn).inMicroseconds;
+    result.timeToIsolateSpawnUs =
+        afterSpawn.difference(beforeSpawn).inMicroseconds;
+    onExitReceivePort.close();
+
+    return result;
+  }
+
+  Future<AggregatedResultMessageLatencyAndMemory> measureFor(
+      int minimumMillis) async {
+    final minimumMicros = minimumMillis * 1000;
+    final watch = Stopwatch()..start();
+    final Metric toAfterIsolateSpawnUs = LatencyMetric("${name}ToAfterSpawn");
+    final Metric toStartRunningCodeUs = LatencyMetric("${name}ToStartRunning");
+    final Metric toFinishRunningCodeUs =
+        LatencyMetric("${name}ToFinishRunning");
+    final Metric toExitUs = LatencyMetric("${name}ToExit");
+    final Metric deltaRss = MemoryMetric("${name}Delta");
+    while (watch.elapsedMicroseconds < minimumMicros) {
+      final ResultMessageLatencyAndMemory result = await run();
+      toAfterIsolateSpawnUs.add(result.timeToIsolateSpawnUs);
+      toStartRunningCodeUs.add(result.timeToStartRunningCodeUs);
+      toFinishRunningCodeUs.add(result.timeToFinishRunningCodeUs);
+      toExitUs.add(result.timeToExitUs);
+      deltaRss.add(result.deltaRss);
+    }
+    return AggregatedResultMessageLatencyAndMemory(toAfterIsolateSpawnUs,
+        toStartRunningCodeUs, toFinishRunningCodeUs, toExitUs, deltaRss);
+  }
+
+  Future<AggregatedResultMessageLatencyAndMemory> measure() async {
+    await measureFor(500); // warm-up
+    return measureFor(4000); // actual measurement
+  }
+
+  Future<void> report() async {
+    final AggregatedResultMessageLatencyAndMemory result = await measure();
+    print(result);
+  }
+
+  final String name;
+  RawReceivePort receivePort;
+}
+
+class Metric {
+  Metric({@required this.prefix, @required this.suffix});
+
+  void add(int value) {
+    if (value > max) {
+      max = value;
+    }
+    sum += value;
+    sumOfSquares += value * value;
+    count++;
+  }
+
+  double _average() => sum / count;
+  double _rms() => sqrt(sumOfSquares / count);
+
+  toString() => "$prefix): ${_average()}$suffix\n"
+      "${prefix}Max): $max$suffix\n"
+      "${prefix}RMS): ${_rms()}$suffix";
+
+  final String prefix;
+  final String suffix;
+  int max = 0;
+  double sum = 0;
+  double sumOfSquares = 0;
+  int count = 0;
+}
+
+class LatencyMetric extends Metric {
+  LatencyMetric(String name) : super(prefix: "${name}(Latency", suffix: " us.");
+}
+
+class MemoryMetric extends Metric {
+  MemoryMetric(String name) : super(prefix: "${name}Rss(MemoryUse", suffix: "");
+
+  toString() => "$prefix): ${_average()}$suffix\n";
+}
+
+class StartMessageLatencyAndMemory {
+  StartMessageLatencyAndMemory(this.sendPort, this.spawned, this.rss);
+
+  final SendPort sendPort;
+  final DateTime spawned;
+  final int rss;
+}
+
+class ResultMessageLatencyAndMemory {
+  ResultMessageLatencyAndMemory(
+      {this.timeToStartRunningCodeUs,
+      this.timeToFinishRunningCodeUs,
+      this.deltaRss});
+
+  final int timeToStartRunningCodeUs;
+  final int timeToFinishRunningCodeUs;
+  final int deltaRss;
+
+  int timeToIsolateSpawnUs;
+  int timeToExitUs;
+}
+
+class AggregatedResultMessageLatencyAndMemory {
+  AggregatedResultMessageLatencyAndMemory(
+    this.toAfterIsolateSpawnUs,
+    this.toStartRunningCodeUs,
+    this.toFinishRunningCodeUs,
+    this.toExitUs,
+    this.deltaRss,
+  );
+
+  String toString() => """$toAfterIsolateSpawnUs
+$toStartRunningCodeUs
+$toFinishRunningCodeUs
+$toExitUs
+$deltaRss""";
+
+  final Metric toAfterIsolateSpawnUs;
+  final Metric toStartRunningCodeUs;
+  final Metric toFinishRunningCodeUs;
+  final Metric toExitUs;
+  final Metric deltaRss;
+}
+
+Future<void> isolateCompiler(StartMessageLatencyAndMemory start) async {
+  final DateTime timeRunningCodeUs = DateTime.now();
+  await runZoned(
+      () => dart2js_main.internalMain(<String>[
+            "benchmarks/IsolateSpawn/dart/helloworld.dart",
+            '--libraries-spec=sdk/lib/libraries.json'
+          ]),
+      zoneSpecification: ZoneSpecification(
+          print: (Zone self, ZoneDelegate parent, Zone zone, String line) {}));
+  final DateTime timeFinishRunningCodeUs = DateTime.now();
+  start.sendPort.send(ResultMessageLatencyAndMemory(
+      timeToStartRunningCodeUs:
+          timeRunningCodeUs.difference(start.spawned).inMicroseconds,
+      timeToFinishRunningCodeUs:
+          timeFinishRunningCodeUs.difference(start.spawned).inMicroseconds,
+      deltaRss: ProcessInfo.currentRss - start.rss));
+}
+
+Future<void> main() async {
+  await SpawnLatencyAndMemory("IsolateSpawn.Dart2JS").report();
+}
diff --git a/benchmarks/IsolateSpawn/dart/helloworld.dart b/benchmarks/IsolateSpawn/dart/helloworld.dart
new file mode 100644
index 0000000..8977e0f
--- /dev/null
+++ b/benchmarks/IsolateSpawn/dart/helloworld.dart
@@ -0,0 +1,3 @@
+main() {
+  print('Hello, world!');
+}
diff --git a/benchmarks/analysis_options.yaml b/benchmarks/analysis_options.yaml
new file mode 100644
index 0000000..8099cf0
--- /dev/null
+++ b/benchmarks/analysis_options.yaml
@@ -0,0 +1,83 @@
+include: package:pedantic/analysis_options.yaml
+#analyzer:
+#  strong-mode:
+#    implicit-casts: false
+linter:
+  rules:
+    #- always_declare_return_types
+    #- annotate_overrides
+    - avoid_empty_else
+    - avoid_function_literals_in_foreach_calls
+    - avoid_init_to_null
+    - avoid_null_checks_in_equality_operators
+    - avoid_relative_lib_imports
+    - avoid_renaming_method_parameters
+    - avoid_return_types_on_setters
+    - avoid_returning_null
+    - avoid_returning_null_for_future
+    - avoid_shadowing_type_parameters
+    - avoid_types_as_parameter_names
+    - avoid_unused_constructor_parameters
+    - await_only_futures
+    - camel_case_types
+    - cancel_subscriptions
+    - comment_references
+    #- constant_identifier_names
+    - control_flow_in_finally
+    - directives_ordering
+    - empty_catches
+    - empty_constructor_bodies
+    - empty_statements
+    - hash_and_equals
+    - implementation_imports
+    - invariant_booleans
+    - iterable_contains_unrelated_type
+    - library_names
+    - library_prefixes
+    - list_remove_unrelated_type
+    - literal_only_boolean_expressions
+    - no_adjacent_strings_in_list
+    - no_duplicate_case_values
+    #- non_constant_identifier_names
+    - null_closures
+    #- omit_local_variable_types
+    #- only_throw_errors
+    - overridden_fields
+    - package_api_docs
+    - package_names
+    - package_prefixed_library_names
+    - prefer_adjacent_string_concatenation
+    - prefer_collection_literals
+    - prefer_conditional_assignment
+    - prefer_const_constructors
+    - prefer_contains
+    - prefer_equal_for_default_values
+    - prefer_generic_function_type_aliases
+    - prefer_final_fields
+    - prefer_final_locals
+    - prefer_initializing_formals
+    - prefer_interpolation_to_compose_strings
+    - prefer_is_empty
+    - prefer_is_not_empty
+    #- prefer_single_quotes
+    #- prefer_typing_uninitialized_variables
+    - recursive_getters
+    - slash_for_doc_comments
+    - test_types_in_equals
+    - throw_in_finally
+    - type_init_formals
+    - unawaited_futures
+    - unnecessary_await_in_return
+    - unnecessary_brace_in_string_interps
+    - unnecessary_const
+    - unnecessary_getters_setters
+    - unnecessary_lambdas
+    - unnecessary_new
+    - unnecessary_null_aware_assignments
+    - unnecessary_parenthesis
+    - unnecessary_statements
+    #- unnecessary_this
+    - unrelated_type_equality_checks
+    - use_function_type_syntax_for_parameters
+    - use_rethrow_when_possible
+    - valid_regexps
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 109e3fc..db31ad4 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -130,6 +130,9 @@
 
   # Compile for Thread Sanitizer to find threading bugs.
   is_tsan = false
+
+  # Compile for Undefined Behavior Sanitizer to find reliance on undefined behavior.
+  is_ubsan = false
 }
 
 # =============================================================================
@@ -198,7 +201,7 @@
 
 # These Sanitizers all imply using the Clang compiler. On Windows they either
 # don't work or work differently.
-if (!is_clang && (is_asan || is_lsan || is_tsan || is_msan)) {
+if (!is_clang && (is_asan || is_lsan || is_msan || is_tsan || is_ubsan)) {
   is_clang = true
 }
 
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index d205e966..b3dec5b 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -36,7 +36,7 @@
 }
 
 if (!is_win) {
-  using_sanitizer = is_asan || is_lsan || is_tsan || is_msan
+  using_sanitizer = is_asan || is_lsan || is_msan || is_tsan || is_ubsan
 }
 
 # compiler ---------------------------------------------------------------------
@@ -109,13 +109,20 @@
       cflags += [ "-fsanitize=leak" ]
       ldflags += [ "-fsanitize=leak" ]
     }
+    if (is_msan) {
+      cflags += [ "-fsanitize=memory" ]
+      ldflags += [ "-fsanitize=memory" ]
+    }
     if (is_tsan) {
       cflags += [ "-fsanitize=thread" ]
       ldflags += [ "-fsanitize=thread" ]
     }
-    if (is_msan) {
-      cflags += [ "-fsanitize=memory" ]
-      ldflags += [ "-fsanitize=memory" ]
+    if (is_ubsan) {
+      cflags += [
+        "-fsanitize=undefined",
+        "-fno-sanitize=null,alignment",
+      ]
+      ldflags += [ "-fsanitize=undefined" ]
     }
   }
 
@@ -238,7 +245,7 @@
   # 2. On Android.
   # 3. When using the sanitizers.
   # Otherwise there is a performance hit, in particular on ia32.
-  if (is_android || is_asan || is_lsan || is_msan || is_tsan ||
+  if (is_android || is_asan || is_lsan || is_msan || is_tsan || is_ubsan ||
       (is_linux && current_cpu != "x86")) {
     cflags += [ "-fPIC" ]
     ldflags += [ "-fPIC" ]
diff --git a/build/config/linux/BUILD.gn b/build/config/linux/BUILD.gn
index 04e5808..9e728c5 100644
--- a/build/config/linux/BUILD.gn
+++ b/build/config/linux/BUILD.gn
@@ -16,7 +16,7 @@
     "-Wl,--exclude-libs=libc++.a",
   ]
 
-  if (is_asan || is_lsan || is_msan || is_tsan) {
+  if (is_asan || is_lsan || is_msan || is_tsan || is_ubsan) {
     ldflags += [ "-lrt" ]
   }
 
diff --git a/build/config/sanitizers/BUILD.gn b/build/config/sanitizers/BUILD.gn
index 8996951..160545a 100644
--- a/build/config/sanitizers/BUILD.gn
+++ b/build/config/sanitizers/BUILD.gn
@@ -11,7 +11,7 @@
   deps = [
     "//third_party/instrumented_libraries:deps",
   ]
-  if (is_asan || is_lsan || is_tsan || is_msan) {
+  if (is_asan || is_lsan || is_msan || is_tsan || is_ubsan) {
     public_configs = [ ":sanitizer_options_link_helper" ]
     deps += [ ":options_sources" ]
   }
@@ -28,11 +28,14 @@
   if (is_lsan) {
     ldflags += [ "-fsanitize=leak" ]
   }
+  if (is_msan) {
+    ldflags += [ "-fsanitize=memory" ]
+  }
   if (is_tsan) {
     ldflags += [ "-fsanitize=thread" ]
   }
-  if (is_msan) {
-    ldflags += [ "-fsanitize=memory" ]
+  if (is_ubsan) {
+    ldflags += [ "-fsanitize=undefined" ]
   }
 }
 
diff --git a/build/config/sanitizers/sanitizers.gni b/build/config/sanitizers/sanitizers.gni
index a66b043..c7da74b 100644
--- a/build/config/sanitizers/sanitizers.gni
+++ b/build/config/sanitizers/sanitizers.gni
@@ -6,7 +6,8 @@
   # Use libc++ (buildtools/third_party/libc++ and
   # buildtools/third_party/libc++abi) instead of stdlibc++ as standard library.
   # This is intended to be used for instrumented builds.
-  use_custom_libcxx = (is_asan && is_linux) || is_lsan || is_msan || is_tsan
+  use_custom_libcxx =
+      (is_asan && is_linux) || is_lsan || is_msan || is_tsan || is_ubsan
 
   # Track where uninitialized memory originates from. From fastest to slowest:
   # 0 - no tracking, 1 - track only the initial allocation site, 2 - track the
diff --git a/build/toolchain/win/BUILD.gn b/build/toolchain/win/BUILD.gn
index 0784d03..ea348b68 100644
--- a/build/toolchain/win/BUILD.gn
+++ b/build/toolchain/win/BUILD.gn
@@ -182,6 +182,8 @@
       # The use of inputs_newline is to work around a fixed per-line buffer
       # size in the linker.
       rspfile_content = "{{libs}} {{solibs}} {{inputs_newline}} {{ldflags}}"
+
+      restat = true
     }
 
     tool("link") {
@@ -206,6 +208,8 @@
       # The use of inputs_newline is to work around a fixed per-line buffer
       # size in the linker.
       rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{ldflags}}"
+
+      restat = true
     }
 
     tool("stamp") {
diff --git a/pkg/analysis_server/benchmark/benchmarks.dart b/pkg/analysis_server/benchmark/benchmarks.dart
index 2cb5f0a..bedacbd 100644
--- a/pkg/analysis_server/benchmark/benchmarks.dart
+++ b/pkg/analysis_server/benchmark/benchmarks.dart
@@ -71,7 +71,7 @@
             'gathering accurate times,\nbut can be used to validate that the '
             'benchmark works.');
     argParser.addOption('repeat',
-        defaultsTo: '10', help: 'The number of times to repeat the benchmark.');
+        defaultsTo: '4', help: 'The number of times to repeat the benchmark.');
     argParser.addFlag('verbose',
         negatable: false,
         help: 'Print all communication to and from the analysis server.');
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 1949461..799e3e7 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -754,10 +754,9 @@
   /// Whether to use the Language Server Protocol.
   bool useLanguageServerProtocol = false;
 
-  /// Whether or not to enable ML code completion.
-  bool enableCompletionModel = false;
-
   /// Base path to locate trained completion language model files.
+  ///
+  /// ML completion is enabled if this is non-null.
   String completionModelFolder;
 
   /// Whether to enable parsing via the Fasta parser.
@@ -915,14 +914,14 @@
   void applyChangesToContext(Folder contextFolder, ChangeSet changeSet) {
     nd.AnalysisDriver analysisDriver = analysisServer.driverMap[contextFolder];
     if (analysisDriver != null) {
-      changeSet.addedSources.forEach((source) {
-        analysisDriver.addFile(source.fullName);
+      changeSet.addedFiles.forEach((path) {
+        analysisDriver.addFile(path);
       });
-      changeSet.changedSources.forEach((source) {
-        analysisDriver.changeFile(source.fullName);
+      changeSet.changedFiles.forEach((path) {
+        analysisDriver.changeFile(path);
       });
-      changeSet.removedSources.forEach((source) {
-        analysisDriver.removeFile(source.fullName);
+      changeSet.removedFiles.forEach((path) {
+        analysisDriver.removeFile(path);
       });
     }
   }
diff --git a/pkg/analysis_server/lib/src/computer/computer_highlights.dart b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
index 0bb5198..7b30a8b 100644
--- a/pkg/analysis_server/lib/src/computer/computer_highlights.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_highlights.dart
@@ -141,18 +141,15 @@
   }
 
   bool _addIdentifierRegion_dynamicType(SimpleIdentifier node) {
-    // should be variable
     Element element = node.staticElement;
-    if (element is! VariableElement) {
-      return false;
+    if (element is VariableElement) {
+      DartType staticType = element.type;
+      if (staticType == null || !staticType.isDynamic) {
+        return false;
+      }
+      return _addRegion_node(node, HighlightRegionType.DYNAMIC_TYPE);
     }
-    // has dynamic static type
-    DartType staticType = node.staticType;
-    if (staticType == null || !staticType.isDynamic) {
-      return false;
-    }
-    // OK
-    return _addRegion_node(node, HighlightRegionType.DYNAMIC_TYPE);
+    return false;
   }
 
   bool _addIdentifierRegion_field(SimpleIdentifier node) {
diff --git a/pkg/analysis_server/lib/src/computer/computer_highlights2.dart b/pkg/analysis_server/lib/src/computer/computer_highlights2.dart
index c3a610b..114a84e 100644
--- a/pkg/analysis_server/lib/src/computer/computer_highlights2.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_highlights2.dart
@@ -144,24 +144,24 @@
   }
 
   bool _addIdentifierRegion_dynamicLocal(SimpleIdentifier node) {
-    // has dynamic static type
-    DartType staticType = node.staticType;
-    if (staticType == null || !staticType.isDynamic) {
-      return false;
-    }
-    // OK
     Element element = node.staticElement;
     if (element is LocalVariableElement) {
-      HighlightRegionType type = node.inDeclarationContext()
-          ? HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_DECLARATION
-          : HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_REFERENCE;
-      return _addRegion_node(node, type);
+      var elementType = element.type;
+      if (elementType?.isDynamic == true) {
+        HighlightRegionType type = node.inDeclarationContext()
+            ? HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_DECLARATION
+            : HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_REFERENCE;
+        return _addRegion_node(node, type);
+      }
     }
     if (element is ParameterElement) {
-      HighlightRegionType type = node.inDeclarationContext()
-          ? HighlightRegionType.DYNAMIC_PARAMETER_DECLARATION
-          : HighlightRegionType.DYNAMIC_PARAMETER_REFERENCE;
-      return _addRegion_node(node, type);
+      var elementType = element.type;
+      if (elementType?.isDynamic == true) {
+        HighlightRegionType type = node.inDeclarationContext()
+            ? HighlightRegionType.DYNAMIC_PARAMETER_DECLARATION
+            : HighlightRegionType.DYNAMIC_PARAMETER_REFERENCE;
+        return _addRegion_node(node, type);
+      }
     }
     return false;
   }
diff --git a/pkg/analysis_server/lib/src/computer/computer_hover.dart b/pkg/analysis_server/lib/src/computer/computer_hover.dart
index 413df0e..54ad29c 100644
--- a/pkg/analysis_server/lib/src/computer/computer_hover.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_hover.dart
@@ -111,11 +111,9 @@
       // types
       {
         AstNode parent = expression.parent;
-        DartType staticType = null;
-        if (element is ParameterElement) {
-          staticType = element.type;
-        } else if (element == null || element is VariableElement) {
-          staticType = expression.staticType;
+        DartType staticType;
+        if (element == null || element is VariableElement) {
+          staticType = _getTypeOfDeclarationOrReference(node);
         }
         if (parent is MethodInvocation && parent.methodName == expression) {
           staticType = parent.staticInvokeType;
@@ -166,5 +164,21 @@
     return null;
   }
 
+  static DartType _getTypeOfDeclarationOrReference(Expression node) {
+    if (node is SimpleIdentifier) {
+      var element = node.staticElement;
+      if (element is VariableElement) {
+        if (node.inDeclarationContext()) {
+          return element.type;
+        }
+        var parent2 = node.parent.parent;
+        if (parent2 is NamedExpression && parent2.name.label == node) {
+          return element.type;
+        }
+      }
+    }
+    return node.staticType;
+  }
+
   static String _safeToString(obj) => obj?.toString();
 }
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index dfb5db4..66a68e8 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -42,6 +42,41 @@
 import 'package:watcher/watcher.dart';
 import 'package:yaml/yaml.dart';
 
+/// An indication of which files have been added, changed, removed, or deleted.
+///
+/// No file should be added to the change set more than once, either with the
+/// same or a different kind of change. It does not make sense, for example,
+/// for a file to be both added and removed.
+class ChangeSet {
+  /// A list containing paths of added files.
+  final List<String> addedFiles = [];
+
+  /// A list containing paths of changed files.
+  final List<String> changedFiles = [];
+
+  /// A list containing paths of removed files.
+  final List<String> removedFiles = [];
+
+  /// Return `true` if this change set does not contain any changes.
+  bool get isEmpty =>
+      addedFiles.isEmpty && changedFiles.isEmpty && removedFiles.isEmpty;
+
+  /// Record that the file with the specified [path] has been added.
+  void addedSource(String path) {
+    addedFiles.add(path);
+  }
+
+  /// Record that the file with the specified [path] has been changed.
+  void changedSource(String path) {
+    changedFiles.add(path);
+  }
+
+  /// Record that the file with the specified [path] has been removed.
+  void removedSource(String path) {
+    removedFiles.add(path);
+  }
+}
+
 /**
  * Information tracked by the [ContextManager] for each context.
  */
@@ -770,7 +805,7 @@
       ChangeSet changeSet = new ChangeSet();
       excludedSources.forEach((String path, Source source) {
         info.sources.remove(path);
-        changeSet.removedSource(source);
+        changeSet.removedSource(path);
       });
       callbacks.applyChangesToContext(info.folder, changeSet);
     }
@@ -819,7 +854,7 @@
         }
         // do add the file
         Source source = createSourceInContext(info.analysisDriver, child);
-        changeSet.addedSource(source);
+        changeSet.addedSource(child.path);
         info.sources[path] = source;
       } else if (child is Folder) {
         _addPreviouslyExcludedSources(info, changeSet, child, oldExcludedPaths);
@@ -854,7 +889,7 @@
       if (child is File) {
         if (_shouldFileBeAnalyzed(child)) {
           Source source = createSourceInContext(info.analysisDriver, child);
-          changeSet.addedSource(source);
+          changeSet.addedSource(child.path);
           info.sources[path] = source;
         }
       } else if (child is Folder) {
@@ -1277,7 +1312,7 @@
       ChangeSet changeSet = new ChangeSet();
       extractedSources.forEach((path, source) {
         newInfo.sources[path] = source;
-        changeSet.addedSource(source);
+        changeSet.addedSource(path);
       });
       callbacks.applyChangesToContext(newFolder, changeSet);
     }
@@ -1286,7 +1321,7 @@
       ChangeSet changeSet = new ChangeSet();
       extractedSources.forEach((path, source) {
         oldInfo.sources.remove(path);
-        changeSet.removedSource(source);
+        changeSet.removedSource(path);
       });
       callbacks.applyChangesToContext(oldInfo.folder, changeSet);
     }
@@ -1568,7 +1603,7 @@
       ChangeSet changeSet = new ChangeSet();
       info.sources.forEach((path, source) {
         parentInfo.sources[path] = source;
-        changeSet.addedSource(source);
+        changeSet.addedSource(path);
       });
       callbacks.applyChangesToContext(parentInfo.folder, changeSet);
     }
diff --git a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
index a04b33f..bc478c5 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
@@ -184,7 +184,7 @@
     if (node.type == null) {
       Token token = node.keyword;
       if (token?.keyword == Keyword.VAR) {
-        DartType inferredType = node.identifier?.staticType;
+        DartType inferredType = node.declaredElement?.type;
         Element element = inferredType?.element;
         if (element != null) {
           computer._addRegionForToken(token, element);
@@ -294,12 +294,12 @@
      * inferred type.
      */
     Element getCommonElement(List<VariableDeclaration> variables) {
-      Element firstElement = variables[0].name?.staticType?.element;
+      Element firstElement = variables[0].declaredElement.type?.element;
       if (firstElement == null) {
         return null;
       }
       for (int i = 1; i < variables.length; i++) {
-        Element element = variables[1].name?.staticType?.element;
+        Element element = variables[1].declaredElement.type?.element;
         if (element != firstElement) {
           return null;
         }
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 0b33895..1cfb93f 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
@@ -222,7 +222,7 @@
     // Gather the data needed in order to produce the output.
     InfoBuilder infoBuilder =
         InfoBuilder(instrumentationListener.data, listener);
-    List<UnitInfo> unitInfos = await infoBuilder.explainMigration();
+    Set<UnitInfo> unitInfos = await infoBuilder.explainMigration();
     var pathContext = provider.pathContext;
     MigrationInfo migrationInfo =
         MigrationInfo(unitInfos, pathContext, includedRoot);
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 576a7a9..e0c0b81 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
@@ -2,6 +2,8 @@
 // for 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';
+
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/domains/analysis/navigation_dart.dart';
 import 'package:analysis_server/src/edit/fix/dartfix_listener.dart';
@@ -52,9 +54,10 @@
 
   /// Return the migration information for all of the libraries that were
   /// migrated.
-  Future<List<UnitInfo>> explainMigration() async {
+  Future<Set<UnitInfo>> explainMigration() async {
     Map<Source, SourceInformation> sourceInfoMap = info.sourceInformation;
-    List<UnitInfo> units = [];
+    Set<UnitInfo> units =
+        SplayTreeSet<UnitInfo>((u1, u2) => u1.path.compareTo(u2.path));
     for (Source source in sourceInfoMap.keys) {
       String filePath = source.fullName;
       AnalysisSession session =
@@ -114,11 +117,13 @@
     AstNode findFunctionBody() {
       if (parent is ExpressionFunctionBody) {
         return parent;
-      } else if (parent is ReturnStatement &&
-          parent.parent?.parent is BlockFunctionBody) {
-        return parent.parent.parent;
+      } else {
+        ReturnStatement returnNode =
+            parent.thisOrAncestorOfType<ReturnStatement>();
+        BlockFunctionBody bodyNode =
+            returnNode?.thisOrAncestorOfType<BlockFunctionBody>();
+        return bodyNode;
       }
-      return null;
     }
 
     AstNode functionBody = findFunctionBody();
@@ -143,6 +148,8 @@
         return "This variable is initialized to null";
       }
       return "This variable is initialized to a nullable value";
+    } else if (parent is AsExpression) {
+      return "The value of the expression is nullable";
     }
     if (node is NullLiteral) {
       return "An explicit 'null' is assigned";
@@ -173,6 +180,37 @@
     return description;
   }
 
+  /// Return a description of the given [origin] associated with the [edge].
+  RegionDetail _buildDetailForOrigin(EdgeOriginInfo origin, EdgeInfo edge) {
+    AstNode node = origin.node;
+    NavigationTarget target;
+    // Some nodes don't need a target; default formal parameters
+    // without explicit default values, for example.
+    if (node is DefaultFormalParameter && node.defaultValue == null) {
+      target = null;
+    } else {
+      if (origin.kind == EdgeOriginKind.inheritance) {
+        // The node is the method declaration in the subclass and we want to
+        // link to the corresponding parameter in the declaration in the
+        // superclass.
+        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.
+        }
+      }
+      target = _targetForNode(origin.source.fullName, node);
+    }
+    return RegionDetail(_buildDescriptionForOrigin(node), target);
+  }
+
   /// Compute the details for the fix with the given [fixInfo].
   List<RegionDetail> _computeDetails(FixInfo fixInfo) {
     List<RegionDetail> details = [];
@@ -182,12 +220,7 @@
           if (edge.isTriggered) {
             EdgeOriginInfo origin = info.edgeOrigin[edge];
             if (origin != null) {
-              // TODO(brianwilkerson) If the origin is an InheritanceOrigin then
-              //  the node is the method declaration in the subclass and we want
-              //  to link to the corresponding parameter in the declaration in
-              //  the superclass.
-              details.add(RegionDetail(_buildDescriptionForOrigin(origin.node),
-                  _targetForNode(origin.source.fullName, origin.node)));
+              details.add(_buildDetailForOrigin(origin, edge));
             } else {
               details.add(
                   RegionDetail('upstream edge with no origin ($edge)', null));
@@ -321,7 +354,32 @@
   /// Return the navigation target corresponding to the given [node] in the file
   /// with the given [filePath].
   NavigationTarget _targetForNode(String filePath, AstNode node) {
-    return _targetFor(filePath, node.offset, node.length);
+    AstNode parent = node.parent;
+    if (node is ConstructorDeclaration) {
+      if (node.name != null) {
+        return _targetFor(filePath, node.name.offset, node.name.length);
+      } else {
+        return _targetFor(
+            filePath, node.returnType.offset, node.returnType.length);
+      }
+    } else if (node is MethodDeclaration) {
+      // Rather than create a NavigationTarget for an entire method declaration
+      // (starting at its doc comment, ending at `}`, return a target pointing
+      // to the method's name.
+      return _targetFor(filePath, node.name.offset, node.name.length);
+    } else if (parent is ReturnStatement) {
+      // Rather than create a NavigationTarget for an entire expression, return
+      // a target pointing to the `return` token.
+      return _targetFor(
+          filePath, parent.returnKeyword.offset, parent.returnKeyword.length);
+    } else if (parent is ExpressionFunctionBody) {
+      // Rather than create a NavigationTarget for an entire expression function
+      // body, return a target pointing to the `=>` token.
+      return _targetFor(filePath, parent.functionDefinition.offset,
+          parent.functionDefinition.length);
+    } else {
+      return _targetFor(filePath, node.offset, node.length);
+    }
   }
 
   /// Return the unit info for the file at the given [path].
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 e1b1938..60e7d38 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
@@ -72,6 +72,21 @@
 //    }
     return null;
   }
+
+  /// Return the type annotation associated with the [node] or `null` if the
+  /// node represents an implicit type.
+  TypeAnnotation typeAnnotationForNode(NullabilityNodeInfo node) {
+    for (MapEntry<Source, SourceInformation> sourceEntry
+        in sourceInformation.entries) {
+      for (MapEntry<TypeAnnotation, NullabilityNodeInfo> typeEntry
+          in sourceEntry.value.explicitTypeNullability.entries) {
+        if (typeEntry.value == node) {
+          return typeEntry.key;
+        }
+      }
+    }
+    return null;
+  }
 }
 
 /// The instrumentation information about a [NullabilityNodeInfo].
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 b243b6f..8caa0b1 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
@@ -2,6 +2,8 @@
 // for 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:convert' show htmlEscape, LineSplitter;
+
 import 'package:analysis_server/src/edit/nnbd_migration/migration_info.dart';
 import 'package:analysis_server/src/edit/nnbd_migration/offset_mapper.dart';
 import 'package:analysis_server/src/edit/nnbd_migration/path_mapper.dart';
@@ -14,32 +16,57 @@
 <html>
   <head>
     <title>Non-nullable fix instrumentation report</title>
-<!--    <script src="{{ highlightJsPath }}"></script>-->
+    <script src="{{ highlightJsPath }}"></script>
     <script>
-    function highlightTarget() {
-      var url = document.URL;
-      var index = url.lastIndexOf("#");
+    function getHash(location) {
+      var index = location.lastIndexOf("#");
       if (index >= 0) {
-        var name = url.substring(index + 1);
-        var anchor = document.getElementById(name);
+        return location.substring(index + 1);
+      } else {
+        return null;
+      }
+    }
+
+    function highlightTarget(event) {
+      if (event !== undefined && event.oldURL !== undefined) {
+        // Remove the "target" CSS class from the previous anchor.
+        var oldHash = getHash(event.oldURL);
+        if (oldHash != null) {
+          var anchor = document.getElementById(oldHash);
+          if (anchor != null) {
+            anchor.classList.remove("target");
+          }
+        }
+      }
+      var url = document.URL;
+      var hash = getHash(url);
+      if (hash != null) {
+        var anchor = document.getElementById(hash);
         if (anchor != null) {
-          anchor.className = "target";
+          anchor.classList.add("target");
         }
       }
     }
+
+    document.addEventListener("DOMContentLoaded", highlightTarget);
+    window.addEventListener("hashchange", highlightTarget);
     </script>
     <link rel="stylesheet" href="{{ highlightStylePath }}">
     <style>
 a:link {
-  color: #000000;
+  color: inherit;
   text-decoration-line: none;
 }
 
 a:visited {
-  color: #000000;
+  color: inherit;
   text-decoration-line: none;
 }
 
+a:hover {
+  text-decoration-line: underline;
+}
+
 body {
   font-family: sans-serif;
   padding: 1em;
@@ -51,8 +78,9 @@
 }
 
 .code {
-  position: absolute;
   left: 0.5em;
+  padding-left: 60px;
+  position: absolute;
   top: 0.5em;
 }
 
@@ -63,6 +91,7 @@
 }
 
 .regions {
+  padding: 0.5em;
   position: absolute;
   left: 0.5em;
   top: 0.5em;
@@ -71,6 +100,28 @@
   visibility: hidden;
 }
 
+.regions table {
+  border-spacing: 0;
+}
+
+.regions td {
+  border: none;
+  padding: 0;
+  white-space: pre;
+}
+
+.regions td:empty:after {
+  content: "\00a0";
+}
+
+.regions td.line-no {
+  color: #999999;
+  padding-right: 4px;
+  text-align: right;
+  visibility: visible;
+  width: 50px;
+}
+
 .region {
   /* Green means this region was added. */
   background-color: #ccffcc;
@@ -99,6 +150,10 @@
   z-index: 1;
 }
 
+.region .tooltip > * {
+  margin: 1em;
+}
+
 .region:hover .tooltip {
   visibility: visible;
 }
@@ -110,7 +165,7 @@
 }
     </style>
   </head>
-  <body onload="highlightTarget()">
+  <body>
     <h1>Non-nullable fix instrumentation report</h1>
     <p><em>Well-written introduction to this report.</em></p>
     <div class="navigation">
@@ -123,37 +178,21 @@
     {{# units }}'''
     '<h2>{{{ path }}}</h2>'
     '<div class="content">'
-//    '<div class="highlighting">'
-//    '{{! These regions are written out, unmodified, as they need to be found }}'
-//    '{{! in one simple text string for highlight.js to hightlight them. }}'
-//    '{{# regions }}'
-//    '{{ content }}'
-//    '{{/ regions }}'
-//    '</div>'
-    '<div class ="code">'
+    '<div class="code">'
     '{{! Write the file content, modified to include navigation information, }}'
     '{{! both anchors and links. }}'
     '{{{ navContent }}}'
     '</div>'
     '<div class="regions">'
-    '{{! The regions are then written again, overlaying the first two copies }}'
-    '{{! of the content, to provide tooltips for modified regions. }}'
-    '{{# regions }}'
-    '{{^ modified }}{{ content }}{{/ modified }}'
-    '{{# modified }}<span class="region">{{ content }}'
-    '<span class="tooltip">{{ explanation }}<ul>'
-    '{{# details }}'
-    '<li>'
-    '<a href="{{ target }}">{{ description }}</a>'
-    '</li>'
-    '{{/ details }}</ul></span></span>{{/ modified }}'
-    '{{/ regions }}'
+    '{{! The regions are then written again, overlaying the first copy of }}'
+    '{{! the content, to provide tooltips for modified regions. }}'
+    '{{{ regionContent }}}'
     '</div></div>'
     r'''
     {{/ units }}
     <script lang="javascript">
 document.addEventListener("DOMContentLoaded", (event) => {
-  document.querySelectorAll(".highlighting").forEach((block) => {
+  document.querySelectorAll(".code").forEach((block) => {
     hljs.highlightBlock(block);
   });
 });
@@ -178,10 +217,11 @@
   /// Creates an output object for the given library info.
   InstrumentationRenderer(this.unitInfo, this.migrationInfo, this.pathMapper);
 
+  /// Return the path context used to manipulate paths.
+  path.Context get pathContext => migrationInfo.pathContext;
+
   /// Builds an HTML view of the instrumentation information in [unitInfo].
   String render() {
-    // TODO(brianwilkerson) Restore syntactic highlighting.
-    // TODO(brianwilkerson) Add line numbers beside the content.
     Map<String, dynamic> mustacheContext = {
       'units': <Map<String, dynamic>>[],
       'links': migrationInfo.unitLinks(unitInfo),
@@ -191,140 +231,156 @@
     };
     mustacheContext['units'].add({
       'path': unitInfo.path,
-      'regions': _computeRegions(unitInfo),
+      'regionContent': _computeRegionContent(unitInfo),
     });
     return _template.renderString(mustacheContext);
   }
 
   /// Return the content of the file with navigation links and anchors added.
   String _computeNavigationContent(UnitInfo unitInfo) {
+    String unitDir = _directoryContaining(unitInfo);
     String content = unitInfo.content;
     OffsetMapper mapper = unitInfo.offsetMapper;
-    List<NavigationRegion> regions = []
-      ..addAll(unitInfo.sources ?? <NavigationSource>[])
-      ..addAll(unitInfo.targets);
-    regions.sort((first, second) {
-      int offsetComparison = first.offset.compareTo(second.offset);
-      if (offsetComparison == 0) {
-        return first is NavigationSource ? -1 : 1;
-      }
-      return offsetComparison;
-    });
+    Map<int, String> openInsertions = {};
+    Map<int, String> closeInsertions = {};
+    //
+    // Compute insertions for navigation targets.
+    //
+    for (NavigationTarget region in unitInfo.targets) {
+      int openOffset = mapper.map(region.offset);
+      String openInsertion = openInsertions[openOffset] ?? '';
+      openInsertion = '<a id="o${region.offset}">$openInsertion';
+      openInsertions[openOffset] = openInsertion;
 
-    StringBuffer navContent = StringBuffer();
-    int previousOffset = 0;
-    for (int i = 0; i < regions.length; i++) {
-      NavigationRegion region = regions[i];
-      int offset = mapper.map(region.offset);
-      int length = region.length;
-      if (offset > previousOffset) {
-        // Write a non-target region.
-        navContent.write(content.substring(previousOffset, offset));
-        if (region is NavigationSource) {
-          if (i + 1 < regions.length &&
-              regions[i + 1].offset == region.offset) {
-            NavigationTarget target = region.target;
-            if (target == regions[i + 1]) {
-              // Add a target region. We skip the source because it links to
-              // itself, which is pointless.
-              navContent.write('<a id="o${region.offset}">');
-              navContent.write(content.substring(offset, offset + length));
-              navContent.write('</a>');
-            } else {
-              // Add a source and target region.
-              // TODO(brianwilkerson) Map the target's file path to the path of
-              //  the corresponding html file. I'd like to do this by adding a
-              //  `FilePathMapper` object so that it can't become inconsistent
-              //  with the code used to decide where to write the html.
-              String htmlPath = pathMapper.map(target.filePath);
-              navContent.write('<a id="o${region.offset}" ');
-              navContent.write('href="$htmlPath#o${target.offset}">');
-              navContent.write(content.substring(offset, offset + length));
-              navContent.write('</a>');
-            }
-            i++;
-          } else {
-            // Add a source region.
-            NavigationTarget target = region.target;
-            String htmlPath = pathMapper.map(target.filePath);
-            navContent.write('<a href="$htmlPath#o${target.offset}">');
-            navContent.write(content.substring(offset, offset + length));
-            navContent.write('</a>');
-          }
-        } else {
-          // Add a target region.
-          navContent.write('<a id="o${region.offset}">');
-          navContent.write(content.substring(offset, offset + length));
-          navContent.write('</a>');
-        }
-        previousOffset = offset + length;
+      int closeOffset = openOffset + region.length;
+      String closeInsertion = closeInsertions[closeOffset] ?? '';
+      closeInsertion = '$closeInsertion</a>';
+      closeInsertions[closeOffset] = closeInsertion;
+    }
+    //
+    // Compute insertions for navigation sources, but skip the sources that
+    // point at themselves.
+    //
+    for (NavigationSource region in unitInfo.sources ?? <NavigationSource>[]) {
+      int openOffset = mapper.map(region.offset);
+      NavigationTarget target = region.target;
+      if (target.filePath != unitInfo.path || region.offset != target.offset) {
+        String openInsertion = openInsertions[openOffset] ?? '';
+        String htmlPath = pathContext.relative(pathMapper.map(target.filePath),
+            from: unitDir);
+        openInsertion = '<a href="$htmlPath#o${target.offset}">$openInsertion';
+        openInsertions[openOffset] = openInsertion;
+
+        int closeOffset = openOffset + region.length;
+        String closeInsertion = closeInsertions[closeOffset] ?? '';
+        closeInsertion = '$closeInsertion</a>';
+        closeInsertions[closeOffset] = closeInsertion;
       }
     }
-    if (previousOffset < content.length) {
-      // Last non-target region.
-      navContent.write(content.substring(previousOffset));
+    //
+    // Apply the insertions that have been computed.
+    //
+    List<int> offsets = []
+      ..addAll(openInsertions.keys)
+      ..addAll(closeInsertions.keys);
+    offsets.sort();
+    StringBuffer navContent2 = StringBuffer();
+    int previousOffset2 = 0;
+    for (int offset in offsets) {
+      navContent2.write(content.substring(previousOffset2, offset));
+      navContent2.write(closeInsertions[offset] ?? '');
+      navContent2.write(openInsertions[offset] ?? '');
+      previousOffset2 = offset;
     }
-    return navContent.toString();
+    if (previousOffset2 < content.length) {
+      navContent2.write(content.substring(previousOffset2));
+    }
+    return navContent2.toString();
   }
 
-  /// Return a list of Mustache context, based on the [unitInfo] for both
-  /// unmodified and modified regions:
-  ///
-  /// * 'modified': Whether this region represents modified source, or
-  ///   unmodified.
-  /// * 'content': The textual content of this region.
-  /// * 'explanation': The Mustache context for the tooltip explaining why the
-  ///   content in this region was modified.
-  List<Map> _computeRegions(UnitInfo unitInfo) {
+  /// Return the content of regions, based on the [unitInfo] for both
+  /// unmodified and modified regions.
+  String _computeRegionContent(UnitInfo unitInfo) {
+    String unitDir = _directoryContaining(unitInfo);
     String content = unitInfo.content;
-    List<Map> regions = [];
+    StringBuffer regions = StringBuffer();
+    int lineNumber = 1;
+
+    void writeSplitLines(String lines) {
+      Iterator<String> lineIterator = LineSplitter.split(lines).iterator;
+      lineIterator.moveNext();
+
+      while (true) {
+        regions.write(htmlEscape.convert(lineIterator.current));
+        if (lineIterator.moveNext()) {
+          // If we're not on the last element, end this table row, and start a
+          // new table row.
+          lineNumber++;
+          regions.write(
+              '</td></tr>' '<tr><td class="line-no">$lineNumber</td><td>');
+        } else {
+          break;
+        }
+      }
+    }
+
     int previousOffset = 0;
+    regions.write('<table><tbody><tr><td class="line-no">$lineNumber</td><td>');
     for (var region in unitInfo.regions) {
       int offset = region.offset;
       int length = region.length;
       if (offset > previousOffset) {
         // Display a region of unmodified content.
-        regions.add({
-          'modified': false,
-          'content': content.substring(previousOffset, offset),
-        });
+        writeSplitLines(content.substring(previousOffset, offset));
         previousOffset = offset + length;
       }
-      List<Map> details = [];
-      for (var detail in region.details) {
-        details.add({
-          'description': detail.description,
-          'target': _uriForTarget(detail.target),
-        });
+      regions.write('<span class="region">'
+          '${content.substring(offset, offset + length)}'
+          '<span class="tooltip">'
+          '<p>${region.explanation}</p>');
+      if (region.details.isNotEmpty) {
+        regions.write('<ul>');
       }
-      regions.add({
-        'modified': true,
-        'content': content.substring(offset, offset + length),
-        'explanation': region.explanation,
-        'details': details,
-      });
+      for (var detail in region.details) {
+        regions.write('<li>');
+
+        if (detail.target != null) {
+          regions.write('<a href="${_uriForTarget(detail.target, unitDir)}">');
+        }
+        writeSplitLines(detail.description);
+        if (detail.target != null) {
+          regions.write('</a>');
+        }
+        regions.write('</li>');
+      }
+      if (region.details.isNotEmpty) {
+        regions.write('</ul>');
+      }
+      regions.write('</span></span>');
     }
     if (previousOffset < content.length) {
       // Last region of unmodified content.
-      regions.add({
-        'modified': false,
-        'content': content.substring(previousOffset),
-      });
+      writeSplitLines(content.substring(previousOffset));
     }
-    return regions;
+    regions.write('</td></tr></tbody></table>');
+    return regions.toString();
+  }
+
+  /// Return the path to the directory containing the output generated from the
+  /// [unitInfo].
+  String _directoryContaining(UnitInfo unitInfo) {
+    return pathContext.dirname(pathMapper.map(unitInfo.path));
   }
 
   /// Return the URL that will navigate to the given [target].
-  String _uriForTarget(NavigationTarget target) {
+  String _uriForTarget(NavigationTarget target, String unitDir) {
     if (target == null) {
       // TODO(brianwilkerson) This is temporary support until we can get targets
       //  for all nodes.
       return '';
     }
-    path.Context pathContext = migrationInfo.pathContext;
-    String targetPath = pathContext.setExtension(target.filePath, '.html');
-    String sourceDir = pathContext.dirname(unitInfo.path);
-    String relativePath = pathContext.relative(targetPath, from: sourceDir);
+    String relativePath =
+        pathContext.relative(pathMapper.map(target.filePath), from: unitDir);
     return '$relativePath#o${target.offset.toString()}';
   }
 }
@@ -336,7 +392,7 @@
 /// instrumentation output.
 class MigrationInfo {
   /// The information about the compilation units that are are migrated.
-  final List<UnitInfo> units;
+  final Set<UnitInfo> units;
 
   /// The resource provider's path context.
   final path.Context pathContext;
@@ -347,14 +403,14 @@
   MigrationInfo(this.units, this.pathContext, this.includedRoot);
 
   /// The path to the highlight.js script, relative to [unitInfo].
-  String highlightJsPath(UnitInfo unitInfo) =>
-      pathContext.relative(pathContext.join(includedRoot, 'highlight.pack.js'),
-          from: pathContext.dirname(unitInfo.path));
+  String highlightJsPath(UnitInfo unitInfo) => pathContext.relative(
+      pathContext.join(includedRoot, '..', 'highlight.pack.js'),
+      from: pathContext.dirname(unitInfo.path));
 
   /// The path to the highlight.js stylesheet, relative to [unitInfo].
-  String highlightStylePath(UnitInfo unitInfo) =>
-      pathContext.relative(pathContext.join(includedRoot, 'androidstudio.css'),
-          from: pathContext.dirname(unitInfo.path));
+  String highlightStylePath(UnitInfo unitInfo) => pathContext.relative(
+      pathContext.join(includedRoot, '..', 'androidstudio.css'),
+      from: pathContext.dirname(unitInfo.path));
 
   /// Generate mustache context for unit links, for navigation in the
   /// instrumentation document for [thisUnit].
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 57f6002..e2ee753 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
@@ -9,7 +9,7 @@
 class LibraryInfo {
   /// The information about the units in the library. The information about the
   /// defining compilation unit is always first.
-  final List<UnitInfo> units;
+  final Set<UnitInfo> units;
 
   /// Initialize a newly created library.
   LibraryInfo(this.units);
@@ -55,6 +55,9 @@
         other.offset == offset &&
         other.length == length;
   }
+
+  @override
+  String toString() => 'NavigationTarget["$filePath", $offset, $length]';
 }
 
 /// An additional detail related to a region.
diff --git a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
index f54a863..0f6f7ab 100644
--- a/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
+++ b/pkg/analysis_server/lib/src/lsp/lsp_analysis_server.dart
@@ -645,14 +645,14 @@
   void applyChangesToContext(Folder contextFolder, ChangeSet changeSet) {
     nd.AnalysisDriver analysisDriver = analysisServer.driverMap[contextFolder];
     if (analysisDriver != null) {
-      changeSet.addedSources.forEach((source) {
-        analysisDriver.addFile(source.fullName);
+      changeSet.addedFiles.forEach((path) {
+        analysisDriver.addFile(path);
       });
-      changeSet.changedSources.forEach((source) {
-        analysisDriver.changeFile(source.fullName);
+      changeSet.changedFiles.forEach((path) {
+        analysisDriver.changeFile(path);
       });
-      changeSet.removedSources.forEach((source) {
-        analysisDriver.removeFile(source.fullName);
+      changeSet.removedFiles.forEach((path) {
+        analysisDriver.removeFile(path);
       });
     }
   }
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index 15e715c..02e74bc 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -348,20 +348,27 @@
     analysisServerOptions.cacheFolder = results[CACHE_FOLDER];
     analysisServerOptions.useFastaParser = results[USE_FASTA_PARSER];
     analysisServerOptions.useLanguageServerProtocol = results[USE_LSP];
+
+    final bool enableCompletionModel = results[ENABLE_COMPLETION_MODEL];
     analysisServerOptions.completionModelFolder =
         results[COMPLETION_MODEL_FOLDER];
-    if (results[ENABLE_COMPLETION_MODEL] &&
+    if (results.wasParsed(ENABLE_COMPLETION_MODEL) && !enableCompletionModel) {
+      // This is the case where the user has explicitly turned off model-based
+      // code completion.
+      analysisServerOptions.completionModelFolder = null;
+    }
+    if (enableCompletionModel &&
         analysisServerOptions.completionModelFolder == null) {
-      // The user has enabled ML code completion without explicitly setting
-      // a model for us to choose, so use the default one. We need to walk over
+      // The user has enabled ML code completion without explicitly setting a
+      // model for us to choose, so use the default one. We need to walk over
       // from $SDK/bin/snapshots/analysis_server.dart.snapshot to
-      // $SDK/model/lexeme.
+      // $SDK/bin/model/lexeme.
       analysisServerOptions.completionModelFolder = path.join(
-          File.fromUri(Platform.script).parent.path,
-          '..',
-          '..',
-          'model',
-          'lexeme');
+        File.fromUri(Platform.script).parent.path,
+        '..',
+        'model',
+        'lexeme',
+      );
     }
 
     bool disableAnalyticsForSession = results[SUPPRESS_ANALYTICS_FLAG];
@@ -591,13 +598,15 @@
       SocketServer socketServer,
       LspSocketServer lspSocketServer,
       AnalysisServerOptions analysisServerOptions) {
+    // If ML completion is not enabled, or we're on a 32-bit machine, don't try
+    // and start the completion model.
     if (analysisServerOptions.completionModelFolder == null ||
         ffi.sizeOf<ffi.IntPtr>() == 4) {
       return;
     }
 
-    // Start completion model isolate if this is a 64 bit system and
-    // analysis server was configured to load a language model on disk.
+    // Start completion model isolate if this is a 64 bit system and analysis
+    // server was configured to load a language model on disk.
     CompletionRanking.instance =
         CompletionRanking(analysisServerOptions.completionModelFolder);
     CompletionRanking.instance.start().catchError((error) {
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.dart b/pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.dart
index 7da0e3e..698c240 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/common_usage_sorter.dart
@@ -57,14 +57,11 @@
     var target = _getCompletionTarget(request);
     if (target != null) {
       var visitor = new _BestTypeVisitor(target.entity);
-      DartType type = target.containingNode.accept(visitor);
-      if (type != null) {
-        Element typeElem = type.element;
-        if (typeElem != null) {
-          LibraryElement libElem = typeElem.library;
-          if (libElem != null) {
-            _updateInvocationRelevance(type, libElem, suggestions);
-          }
+      var typeElem = target.containingNode.accept(visitor);
+      if (typeElem != null) {
+        LibraryElement libElem = typeElem.library;
+        if (libElem != null) {
+          _updateInvocationRelevance(typeElem.name, libElem, suggestions);
         }
       }
     }
@@ -74,9 +71,8 @@
    * Adjusts the relevance of all method suggestions based upon the given
    * target type and library.
    */
-  void _updateInvocationRelevance(DartType type, LibraryElement libElem,
+  void _updateInvocationRelevance(String typeName, LibraryElement libElem,
       Iterable<CompletionSuggestion> suggestions) {
-    String typeName = type.name;
     List<String> selectors = selectorRelevance['${libElem.name}.$typeName'];
     if (selectors != null) {
       for (CompletionSuggestion suggestion in suggestions) {
@@ -102,7 +98,7 @@
 /**
  * An [AstVisitor] used to determine the best defining type of a node.
  */
-class _BestTypeVisitor extends UnifyingAstVisitor<DartType> {
+class _BestTypeVisitor extends UnifyingAstVisitor<Element> {
   /**
    * The entity which the completed text will replace (or which will be
    * displaced once the completed text is inserted).  This may be an AstNode or
@@ -114,32 +110,43 @@
   _BestTypeVisitor(this.entity);
 
   @override
-  DartType visitConstructorName(ConstructorName node) =>
-      node.period != null && node.name == entity ? node.type?.type : null;
+  Element visitConstructorName(ConstructorName node) {
+    return node.period != null && node.name == entity
+        ? node.type?.type?.element
+        : null;
+  }
 
   @override
-  DartType visitNamedExpression(NamedExpression node) {
+  Element visitNamedExpression(NamedExpression node) {
     AstNode parent = node.parent;
     if (parent is ArgumentListImpl) {
       List<ParameterElement> params = parent.correspondingStaticParameters;
       if (params != null) {
         int index = parent.arguments.indexOf(node);
-        return params[index]?.type;
+        return params[index]?.type?.element;
       }
     }
     return super.visitNamedExpression(node);
   }
 
   @override
-  DartType visitNode(AstNode node) {
+  Element visitNode(AstNode node) {
     return null;
   }
 
   @override
-  DartType visitPrefixedIdentifier(PrefixedIdentifier node) =>
-      node.identifier == entity ? node.prefix?.staticType : null;
+  Element visitPrefixedIdentifier(PrefixedIdentifier node) {
+    if (node.identifier == entity) {
+      var type = node.prefix.staticType;
+      if (type is InterfaceType) {
+        return type.element;
+      }
+      return node.prefix.staticElement;
+    }
+    return null;
+  }
 
   @override
-  DartType visitPropertyAccess(PropertyAccess node) =>
-      node.propertyName == entity ? node.realTarget?.staticType : null;
+  Element visitPropertyAccess(PropertyAccess node) =>
+      node.propertyName == entity ? node.realTarget?.staticType?.element : null;
 }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_ranking.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_ranking.dart
index 5858406..5863601 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_ranking.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_ranking.dart
@@ -12,7 +12,7 @@
 import 'package:analyzer/dart/analysis/features.dart';
 
 /// Number of lookback tokens.
-const int _LOOKBACK = 100;
+const int _LOOKBACK = 50;
 
 /// Minimum probability to prioritize model-only suggestion.
 const double _MODEL_RELEVANCE_CUTOFF = 0.5;
@@ -128,7 +128,8 @@
       entries.retainWhere((MapEntry entry) => !isLiteral(entry.key));
     }
 
-    var isRequestFollowingDot = testFollowingDot(request);
+    var allowModelOnlySuggestions =
+        !testNamedArgument(suggestions) && !testFollowingDot(request);
     entries.forEach((MapEntry entry) {
       // There may be multiple like
       // CompletionSuggestion and CompletionSuggestion().
@@ -143,7 +144,7 @@
       } else {
         includedSuggestions = [];
       }
-      if (!isRequestFollowingDot && entry.value > _MODEL_RELEVANCE_CUTOFF) {
+      if (allowModelOnlySuggestions && entry.value > _MODEL_RELEVANCE_CUTOFF) {
         final relevance = high--;
         if (completionSuggestions.isNotEmpty ||
             includedSuggestions.isNotEmpty) {
@@ -170,7 +171,7 @@
         includedSuggestions.forEach((includedSuggestion) {
           includedSuggestion.relevanceBoost = relevance;
         });
-      } else if (!isRequestFollowingDot) {
+      } else if (allowModelOnlySuggestions) {
         final relevance = low--;
         suggestions
             .add(createCompletionSuggestion(entry.key, featureSet, relevance));
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/completion_ranking_internal.dart b/pkg/analysis_server/lib/src/services/completion/dart/completion_ranking_internal.dart
index 318736e..8803712 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/completion_ranking_internal.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/completion_ranking_internal.dart
@@ -72,7 +72,7 @@
     // token is NOT an identifier, keyword, or literal. The rationale is that
     // we want to keep moving if we have a situation like
     // FooBar foo^ since foo is not a previous token to pass to the model.
-    return token.lexeme[token.lexeme.length - 1]
+    return !token.lexeme[token.lexeme.length - 1]
         .contains(new RegExp(r'[0-9A-Za-z_]'));
   }
   // Stop if the token's location is strictly before the cursor, continue
@@ -144,6 +144,16 @@
   return isTokenDot(token) || isTokenDot(token.previous);
 }
 
+/// Tests whether all completion suggestions are for named arguments.
+bool testNamedArgument(List<CompletionSuggestion> suggestions) {
+  if (suggestions == null) {
+    return false;
+  }
+
+  return suggestions.any((CompletionSuggestion suggestion) =>
+      suggestion.kind == CompletionSuggestionKind.NAMED_ARGUMENT);
+}
+
 /// Finds the previous n tokens occurring before the cursor.
 List<String> constructQuery(DartCompletionRequest request, int n) {
   var token = getCursorToken(request);
@@ -164,6 +174,12 @@
       size < n && token != null && !token.isEof;
       token = token.previous) {
     if (!token.isSynthetic && token is! ErrorToken) {
+      // Omit the optional new keyword as we remove it at training time to
+      // prevent model from suggesting it.
+      if (token.lexeme == 'new') {
+        continue;
+      }
+
       result.add(token.lexeme);
       size += 1;
     }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/language_model.dart b/pkg/analysis_server/lib/src/services/completion/dart/language_model.dart
index 67a4ebc..00308b0 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/language_model.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/language_model.dart
@@ -13,6 +13,7 @@
 /// Interface to TensorFlow-based Dart language model for next-token prediction.
 class LanguageModel {
   static const _defaultCompletions = 100;
+  static final _numeric = RegExp(r'^\d+(.\d+)?$');
 
   final tfl.Interpreter _interpreter;
   final Map<String, int> _word2idx;
@@ -63,48 +64,71 @@
   /// Predicts the next token to follow a list of precedent tokens
   ///
   /// Returns a list of tokens, sorted by most probable first.
-  List<String> predict(Iterable<String> tokens) =>
+  List<String> predict(List<String> tokens) =>
       predictWithScores(tokens).keys.toList();
 
   /// Predicts the next token with confidence scores.
   ///
   /// Returns an ordered map of tokens to scores, sorted by most probable first.
-  Map<String, double> predictWithScores(Iterable<String> tokens) {
+  Map<String, double> predictWithScores(List<String> tokens) {
     final tensorIn = _interpreter.getInputTensors().single;
     tensorIn.data = _transformInput(tokens);
     _interpreter.invoke();
     final tensorOut = _interpreter.getOutputTensors().single;
-    return _transformOutput(tensorOut.data);
+    return _transformOutput(tensorOut.data, tokens);
   }
 
   /// Transforms tokens to data bytes that can be used as interpreter input.
-  List<int> _transformInput(Iterable<String> tokens) {
+  List<int> _transformInput(List<String> tokens) {
     // Replace out of vocabulary tokens.
-    final sanitizedTokens = tokens
-        .map((token) => _word2idx.containsKey(token) ? token : '<unknown>');
-
+    final sanitizedTokens = tokens.map((token) {
+      if (_word2idx.containsKey(token)) {
+        return token;
+      }
+      if (_numeric.hasMatch(token)) {
+        return '<num>';
+      }
+      if (_isString(token)) {
+        return '<str>';
+      }
+      return '<unk>';
+    });
     // Get indexes (as floats).
     final indexes = Float32List(lookback)
       ..setAll(0, sanitizedTokens.map((token) => _word2idx[token].toDouble()));
-
     // Get bytes
     return Uint8List.view(indexes.buffer);
   }
 
   /// Transforms interpreter output data to map of tokens to scores.
-  Map<String, double> _transformOutput(List<int> databytes) {
+  Map<String, double> _transformOutput(
+      List<int> databytes, List<String> tokens) {
     // Get bytes.
     final bytes = Uint8List.fromList(databytes);
 
     // Get scores (as floats)
     final probabilities = Float32List.view(bytes.buffer);
 
-    // Get indexes with scores, sorted by scores (descending)
-    final entries = probabilities.asMap().entries.toList()
-      ..sort((a, b) => b.value.compareTo(a.value));
+    final scores = Map<String, double>();
+    probabilities.asMap().forEach((k, v) {
+      // x in 0, 1, ..., |V| - 1 correspond to specific members of the vocabulary.
+      // x in |V|, |V| + 1, ..., |V| + 49 are pointers to reference positions along the
+      // network input.
+      if (k >= _idx2word.length + tokens.length) {
+        return;
+      }
+      final lexeme =
+          k < _idx2word.length ? _idx2word[k] : tokens[k - _idx2word.length];
+      final sanitized = lexeme.replaceAll('"', '\'');
+      scores[sanitized] = (scores[sanitized] ?? 0.0) + v;
+    });
 
-    // Get tokens with scores, limiting the length.
-    return Map.fromEntries(entries.sublist(0, completions))
-        .map((k, v) => MapEntry(_idx2word[k].replaceAll('"', '\''), v));
+    final entries = scores.entries.toList()
+      ..sort((a, b) => b.value.compareTo(a.value));
+    return Map.fromEntries(entries.sublist(0, completions));
+  }
+
+  bool _isString(String token) {
+    return token.indexOf('"') != -1 || token.indexOf("'") != -1;
   }
 }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
index 1e2b426..22ea7d3 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/local_reference_contributor.dart
@@ -17,12 +17,14 @@
 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/generated/resolver.dart';
 import 'package:analyzer/src/util/comment.dart';
 import 'package:analyzer_plugin/protocol/protocol_common.dart' as protocol
     show Element, ElementKind;
 import 'package:analyzer_plugin/src/utilities/completion/optype.dart';
 import 'package:analyzer_plugin/src/utilities/visitors/local_declaration_visitor.dart'
     show LocalDeclarationVisitor;
+import 'package:meta/meta.dart';
 
 /**
  * A contributor for calculating suggestions for declarations in the local
@@ -116,16 +118,20 @@
 
   List<CompletionSuggestion> get suggestions => suggestionMap.values.toList();
 
+  TypeProvider get typeProvider => request.libraryElement.context.typeProvider;
+
   @override
   void declaredClass(ClassDeclaration declaration) {
     if (optype.includeTypeNameSuggestions) {
       _addLocalSuggestion_includeTypeNameSuggestions(
-          declaration.documentationComment,
-          declaration.name,
-          NO_RETURN_TYPE,
-          protocol.ElementKind.CLASS,
-          isAbstract: declaration.isAbstract,
-          isDeprecated: isDeprecated(declaration));
+        declaration.documentationComment,
+        declaration.name,
+        NO_RETURN_TYPE,
+        protocol.ElementKind.CLASS,
+        isAbstract: declaration.isAbstract,
+        isDeprecated: isDeprecated(declaration),
+        type: _instantiateClassElement(declaration.declaredElement),
+      );
     }
   }
 
@@ -133,12 +139,14 @@
   void declaredClassTypeAlias(ClassTypeAlias declaration) {
     if (optype.includeTypeNameSuggestions) {
       _addLocalSuggestion_includeTypeNameSuggestions(
-          declaration.documentationComment,
-          declaration.name,
-          NO_RETURN_TYPE,
-          protocol.ElementKind.CLASS_TYPE_ALIAS,
-          isAbstract: true,
-          isDeprecated: isDeprecated(declaration));
+        declaration.documentationComment,
+        declaration.name,
+        NO_RETURN_TYPE,
+        protocol.ElementKind.CLASS_TYPE_ALIAS,
+        isAbstract: true,
+        isDeprecated: isDeprecated(declaration),
+        type: _instantiateClassElement(declaration.declaredElement),
+      );
     }
   }
 
@@ -146,16 +154,20 @@
   void declaredEnum(EnumDeclaration declaration) {
     if (optype.includeTypeNameSuggestions) {
       _addLocalSuggestion_includeTypeNameSuggestions(
-          declaration.documentationComment,
-          declaration.name,
-          NO_RETURN_TYPE,
-          protocol.ElementKind.ENUM,
-          isDeprecated: isDeprecated(declaration));
+        declaration.documentationComment,
+        declaration.name,
+        NO_RETURN_TYPE,
+        protocol.ElementKind.ENUM,
+        isDeprecated: isDeprecated(declaration),
+        type: _instantiateClassElement(declaration.declaredElement),
+      );
       for (EnumConstantDeclaration enumConstant in declaration.constants) {
         if (!enumConstant.isSynthetic) {
           _addLocalSuggestion_includeReturnValueSuggestions_enumConstant(
-              enumConstant, declaration,
-              isDeprecated: isDeprecated(declaration));
+            enumConstant,
+            declaration,
+            isDeprecated: isDeprecated(declaration),
+          );
         }
       }
     }
@@ -163,13 +175,15 @@
 
   @override
   void declaredExtension(ExtensionDeclaration declaration) {
-    if (optype.includeReturnValueSuggestions) {
+    if (optype.includeReturnValueSuggestions && declaration.name != null) {
       _addLocalSuggestion_includeReturnValueSuggestions(
-          declaration.documentationComment,
-          declaration.name,
-          NO_RETURN_TYPE,
-          protocol.ElementKind.EXTENSION,
-          isDeprecated: isDeprecated(declaration));
+        declaration.documentationComment,
+        declaration.name,
+        NO_RETURN_TYPE,
+        protocol.ElementKind.EXTENSION,
+        isDeprecated: isDeprecated(declaration),
+        type: null,
+      );
     }
   }
 
@@ -181,13 +195,15 @@
       bool deprecated = isDeprecated(fieldDecl) || isDeprecated(varDecl);
       TypeAnnotation typeName = fieldDecl.fields.type;
       _addLocalSuggestion_includeReturnValueSuggestions(
-          fieldDecl.documentationComment,
-          varDecl.name,
-          typeName,
-          protocol.ElementKind.FIELD,
-          isDeprecated: deprecated,
-          relevance: DART_RELEVANCE_LOCAL_FIELD,
-          classDecl: fieldDecl.parent);
+        fieldDecl.documentationComment,
+        varDecl.name,
+        typeName,
+        protocol.ElementKind.FIELD,
+        isDeprecated: deprecated,
+        relevance: DART_RELEVANCE_LOCAL_FIELD,
+        classDecl: fieldDecl.parent,
+        type: varDecl.declaredElement.type,
+      );
     }
   }
 
@@ -216,13 +232,15 @@
         relevance = DART_RELEVANCE_LOCAL_FUNCTION;
       }
       _addLocalSuggestion_includeReturnValueSuggestions(
-          declaration.documentationComment,
-          declaration.name,
-          typeName,
-          elemKind,
-          isDeprecated: isDeprecated(declaration),
-          param: declaration.functionExpression.parameters,
-          relevance: relevance);
+        declaration.documentationComment,
+        declaration.name,
+        typeName,
+        elemKind,
+        isDeprecated: isDeprecated(declaration),
+        param: declaration.functionExpression.parameters,
+        relevance: relevance,
+        type: declaration.declaredElement.type,
+      );
     }
   }
 
@@ -231,12 +249,14 @@
     if (optype.includeTypeNameSuggestions) {
       // TODO (danrubel) determine parameters and return type
       _addLocalSuggestion_includeTypeNameSuggestions(
-          declaration.documentationComment,
-          declaration.name,
-          declaration.returnType,
-          protocol.ElementKind.FUNCTION_TYPE_ALIAS,
-          isAbstract: true,
-          isDeprecated: isDeprecated(declaration));
+        declaration.documentationComment,
+        declaration.name,
+        declaration.returnType,
+        protocol.ElementKind.FUNCTION_TYPE_ALIAS,
+        isAbstract: true,
+        isDeprecated: isDeprecated(declaration),
+        type: _instantiateFunctionTypeAlias(declaration.declaredElement),
+      );
     }
   }
 
@@ -245,12 +265,14 @@
     if (optype.includeTypeNameSuggestions) {
       // TODO (danrubel) determine parameters and return type
       _addLocalSuggestion_includeTypeNameSuggestions(
-          declaration.documentationComment,
-          declaration.name,
-          declaration.functionType?.returnType,
-          protocol.ElementKind.FUNCTION_TYPE_ALIAS,
-          isAbstract: true,
-          isDeprecated: isDeprecated(declaration));
+        declaration.documentationComment,
+        declaration.name,
+        declaration.functionType?.returnType,
+        protocol.ElementKind.FUNCTION_TYPE_ALIAS,
+        isAbstract: true,
+        isDeprecated: isDeprecated(declaration),
+        type: _instantiateFunctionTypeAlias(declaration.declaredElement),
+      );
     }
   }
 
@@ -263,8 +285,14 @@
   void declaredLocalVar(SimpleIdentifier id, TypeAnnotation typeName) {
     if (optype.includeReturnValueSuggestions) {
       _addLocalSuggestion_includeReturnValueSuggestions(
-          null, id, typeName, protocol.ElementKind.LOCAL_VARIABLE,
-          relevance: DART_RELEVANCE_LOCAL_VARIABLE);
+        null,
+        id,
+        typeName,
+        protocol.ElementKind.LOCAL_VARIABLE,
+        relevance: DART_RELEVANCE_LOCAL_VARIABLE,
+        type: (id.staticElement as LocalVariableElement)?.type ??
+            typeProvider.dynamicType,
+      );
     }
   }
 
@@ -297,15 +325,17 @@
         relevance = DART_RELEVANCE_LOCAL_METHOD;
       }
       _addLocalSuggestion_includeReturnValueSuggestions(
-          declaration.documentationComment,
-          declaration.name,
-          typeName,
-          elemKind,
-          isAbstract: declaration.isAbstract,
-          isDeprecated: isDeprecated(declaration),
-          classDecl: declaration.parent,
-          param: param,
-          relevance: relevance);
+        declaration.documentationComment,
+        declaration.name,
+        typeName,
+        elemKind,
+        isAbstract: declaration.isAbstract,
+        isDeprecated: isDeprecated(declaration),
+        classDecl: declaration.parent,
+        param: param,
+        relevance: relevance,
+        type: declaration.declaredElement.type,
+      );
     }
   }
 
@@ -313,12 +343,14 @@
   void declaredMixin(MixinDeclaration declaration) {
     if (optype.includeTypeNameSuggestions) {
       _addLocalSuggestion_includeTypeNameSuggestions(
-          declaration.documentationComment,
-          declaration.name,
-          NO_RETURN_TYPE,
-          protocol.ElementKind.MIXIN,
-          isAbstract: true,
-          isDeprecated: isDeprecated(declaration));
+        declaration.documentationComment,
+        declaration.name,
+        NO_RETURN_TYPE,
+        protocol.ElementKind.MIXIN,
+        isAbstract: true,
+        isDeprecated: isDeprecated(declaration),
+        type: _instantiateClassElement(declaration.declaredElement),
+      );
     }
   }
 
@@ -326,8 +358,13 @@
   void declaredParam(SimpleIdentifier id, TypeAnnotation typeName) {
     if (optype.includeReturnValueSuggestions) {
       _addLocalSuggestion_includeReturnValueSuggestions(
-          null, id, typeName, protocol.ElementKind.PARAMETER,
-          relevance: DART_RELEVANCE_PARAMETER);
+        null,
+        id,
+        typeName,
+        protocol.ElementKind.PARAMETER,
+        relevance: DART_RELEVANCE_PARAMETER,
+        type: (id.staticElement as VariableElement).type,
+      );
     }
   }
 
@@ -336,12 +373,14 @@
       VariableDeclarationList varList, VariableDeclaration varDecl) {
     if (optype.includeReturnValueSuggestions) {
       _addLocalSuggestion_includeReturnValueSuggestions(
-          varDecl.documentationComment,
-          varDecl.name,
-          varList.type,
-          protocol.ElementKind.TOP_LEVEL_VARIABLE,
-          isDeprecated: isDeprecated(varList) || isDeprecated(varDecl),
-          relevance: DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE);
+        varDecl.documentationComment,
+        varDecl.name,
+        varList.type,
+        protocol.ElementKind.TOP_LEVEL_VARIABLE,
+        isDeprecated: isDeprecated(varList) || isDeprecated(varDecl),
+        relevance: DART_RELEVANCE_LOCAL_TOP_LEVEL_VARIABLE,
+        type: varDecl.declaredElement.type,
+      );
     }
   }
 
@@ -438,9 +477,9 @@
       bool isDeprecated = false,
       ClassOrMixinDeclaration classDecl,
       FormalParameterList param,
-      int relevance = DART_RELEVANCE_DEFAULT}) {
-    relevance = optype.returnValueSuggestionsFilter(
-        _staticTypeOfIdentifier(id), relevance);
+      int relevance = DART_RELEVANCE_DEFAULT,
+      @required DartType type}) {
+    relevance = optype.returnValueSuggestionsFilter(type, relevance);
     if (relevance != null) {
       _addLocalSuggestion(documentationComment, id, typeName, elemKind,
           isAbstract: isAbstract,
@@ -477,9 +516,9 @@
       bool isDeprecated = false,
       ClassDeclaration classDecl,
       FormalParameterList param,
-      int relevance = DART_RELEVANCE_DEFAULT}) {
-    relevance = optype.typeNameSuggestionsFilter(
-        _staticTypeOfIdentifier(id), relevance);
+      int relevance = DART_RELEVANCE_DEFAULT,
+      @required DartType type}) {
+    relevance = optype.typeNameSuggestionsFilter(type, relevance);
     if (relevance != null) {
       _addLocalSuggestion(documentationComment, id, typeName, elemKind,
           isAbstract: isAbstract,
@@ -542,7 +581,6 @@
     var typeParameters = element.typeParameters;
     var typeArguments = const <DartType>[];
     if (typeParameters.isNotEmpty) {
-      var typeProvider = request.libraryElement.context.typeProvider;
       typeArguments = typeParameters.map((t) {
         return typeProvider.dynamicType;
       }).toList();
@@ -558,6 +596,25 @@
     );
   }
 
+  FunctionType _instantiateFunctionTypeAlias(FunctionTypeAliasElement element) {
+    var typeParameters = element.typeParameters;
+    var typeArguments = const <DartType>[];
+    if (typeParameters.isNotEmpty) {
+      typeArguments = typeParameters.map((t) {
+        return typeProvider.dynamicType;
+      }).toList();
+    }
+
+    var nullabilitySuffix = request.featureSet.isEnabled(Feature.non_nullable)
+        ? NullabilitySuffix.none
+        : NullabilitySuffix.star;
+
+    return element.instantiate2(
+      typeArguments: typeArguments,
+      nullabilitySuffix: nullabilitySuffix,
+    );
+  }
+
   bool _isVoid(TypeAnnotation returnType) {
     if (returnType is TypeName) {
       Identifier id = returnType.name;
@@ -568,14 +625,6 @@
     return false;
   }
 
-  DartType _staticTypeOfIdentifier(Identifier id) {
-    if (id.staticElement is ClassElement) {
-      return _instantiateClassElement(id.staticElement as ClassElement);
-    } else {
-      return id.staticType;
-    }
-  }
-
   /**
    * If the given [documentationComment] is not `null`, fill the [suggestion]
    * documentation fields.
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 6e3172e..9b4e58a 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
@@ -33,7 +33,9 @@
 
     // Recompute the target since resolution may have changed it
     Expression expression = request.dotTarget;
-    if (expression == null || expression.isSynthetic) {
+    if (expression == null ||
+        expression.isSynthetic ||
+        expression is ExtensionOverride) {
       return const <CompletionSuggestion>[];
     }
     if (expression is Identifier) {
@@ -201,7 +203,8 @@
   @override
   void declaredLocalVar(SimpleIdentifier name, TypeAnnotation type) {
     if (name.name == targetName) {
-      typeFound = name.staticType;
+      var element = name.staticElement as VariableElement;
+      typeFound = element.type;
       finished();
     }
   }
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart b/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
index f7cc0da..e728015 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/utilities.dart
@@ -207,7 +207,7 @@
     }
     type = element.returnType;
   } else if (element is VariableElement) {
-    type = identifier.staticType;
+    type = element.type;
   } else {
     return null;
   }
diff --git a/pkg/analysis_server/lib/src/services/completion/token_details/token_detail_builder.dart b/pkg/analysis_server/lib/src/services/completion/token_details/token_detail_builder.dart
index fbde099..82e057a 100644
--- a/pkg/analysis_server/lib/src/services/completion/token_details/token_detail_builder.dart
+++ b/pkg/analysis_server/lib/src/services/completion/token_details/token_detail_builder.dart
@@ -25,9 +25,24 @@
       if (entity is Token) {
         _createDetails(entity, null, null);
       } else if (entity is SimpleIdentifier) {
-        String type = _getType(entity);
-        if (_isTypeName(entity)) {
-          type = 'dart:core;Type<$type>';
+        String type;
+        var typeNameNode = _getTypeName(entity);
+        if (typeNameNode != null) {
+          var typeStr = _typeStr(typeNameNode.type);
+          type = 'dart:core;Type<$typeStr>';
+        } else if (entity.staticElement is ClassElement) {
+          type = 'Type';
+        } else if (entity.inDeclarationContext()) {
+          var element = entity.staticElement;
+          if (element is FunctionElement) {
+            type = _typeStr(element.type);
+          } else if (element is MethodElement) {
+            type = _typeStr(element.type);
+          } else if (element is VariableElement) {
+            type = _typeStr(element.type);
+          }
+        } else {
+          type = _typeStr(entity.staticType);
         }
         List<String> kinds = [];
         if (entity.inDeclarationContext()) {
@@ -37,13 +52,13 @@
         }
         _createDetails(entity.token, type, kinds);
       } else if (entity is BooleanLiteral) {
-        _createDetails(entity.literal, _getType(entity), null);
+        _createDetails(entity.literal, _typeStr(entity.staticType), null);
       } else if (entity is DoubleLiteral) {
-        _createDetails(entity.literal, _getType(entity), null);
+        _createDetails(entity.literal, _typeStr(entity.staticType), null);
       } else if (entity is IntegerLiteral) {
-        _createDetails(entity.literal, _getType(entity), null);
+        _createDetails(entity.literal, _typeStr(entity.staticType), null);
       } else if (entity is SimpleStringLiteral) {
-        _createDetails(entity.literal, _getType(entity), null);
+        _createDetails(entity.literal, _typeStr(entity.staticType), null);
       } else if (entity is Comment) {
         // Ignore comments and the references within them.
       } else if (entity is AstNode) {
@@ -58,26 +73,26 @@
         type: type, validElementKinds: kinds));
   }
 
-  /// Return a unique identifier for the type of the given [expression].
-  String _getType(Expression expression) {
-    StringBuffer buffer = new StringBuffer();
-    _writeType(buffer, expression.staticType);
-    return buffer.toString();
-  }
-
-  /// Return `true` if the [identifier] represents the name of a type.
-  bool _isTypeName(SimpleIdentifier identifier) {
+  /// Return the [TypeName] with the [identifier].
+  TypeName _getTypeName(SimpleIdentifier identifier) {
     AstNode parent = identifier.parent;
     if (parent is TypeName && identifier == parent.name) {
-      return true;
+      return parent;
     } else if (parent is PrefixedIdentifier &&
         parent.identifier == identifier) {
       AstNode parent2 = parent.parent;
       if (parent2 is TypeName && parent == parent2.name) {
-        return true;
+        return parent2;
       }
     }
-    return false;
+    return null;
+  }
+
+  /// Return a unique identifier for the [type].
+  String _typeStr(DartType type) {
+    StringBuffer buffer = new StringBuffer();
+    _writeType(buffer, type);
+    return buffer.toString();
   }
 
   /// Return a unique identifier for the type of the given [expression].
diff --git a/pkg/analysis_server/lib/src/services/correction/assist.dart b/pkg/analysis_server/lib/src/services/correction/assist.dart
index efbaa0c..ace514e 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist.dart
@@ -31,6 +31,10 @@
  * An enumeration of possible assist kinds.
  */
 class DartAssistKind {
+  static const ADD_DIAGNOSTIC_PROPERTY_REFERENCE = const AssistKind(
+      'ADD_DIAGNOSTIC_PROPERTY_REFERENCE',
+      30,
+      "Add a debug reference to this property");
   static const ADD_NOT_NULL_ASSERT = const AssistKind(
       'dart.assist.addNotNullAssert', 30, "Add a not-null assertion");
   static const ADD_TYPE_ANNOTATION = const AssistKind(
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index 8daaf7b..890f69a 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -156,7 +156,11 @@
     )) {
       await _addProposal_useCurlyBraces();
     }
-
+    if (!_containsErrorCode(
+      {LintNames.diagnostic_describe_all_properties},
+    )) {
+      await _addProposal_addDiagnosticPropertyReference();
+    }
     if (experimentStatus.control_flow_collections) {
       if (!_containsErrorCode(
         {LintNames.prefer_if_elements_to_conditional_expressions},
@@ -3164,6 +3168,12 @@
     _addAssistFromBuilder(changeBuilder, DartAssistKind.USE_CURLY_BRACES);
   }
 
+  Future<void> _addProposal_addDiagnosticPropertyReference() async {
+    final changeBuilder = await createBuilder_addDiagnosticPropertyReference();
+    _addAssistFromBuilder(
+        changeBuilder, DartAssistKind.ADD_DIAGNOSTIC_PROPERTY_REFERENCE);
+  }
+
   Future<void> _addProposals_addTypeAnnotation() async {
     var changeBuilder =
         await createBuilder_addTypeAnnotation_DeclaredIdentifier();
diff --git a/pkg/analysis_server/lib/src/services/correction/base_processor.dart b/pkg/analysis_server/lib/src/services/correction/base_processor.dart
index 4299d23..5fcfaf4 100644
--- a/pkg/analysis_server/lib/src/services/correction/base_processor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/base_processor.dart
@@ -99,26 +99,32 @@
       return null;
     }
 
-    var constructorName;
+    var constructorId;
     var typeArgs;
+    var constructorName = '';
 
-    if (type.isDartCoreInt) {
-      constructorName = 'IntProperty';
+    if (type.element is FunctionTypedElement) {
+      constructorId = 'ObjectFlagProperty';
+      typeArgs = [type];
+      constructorName = '.has';
+    } else if (type.isDartCoreInt) {
+      constructorId = 'IntProperty';
     } else if (type.isDartCoreDouble) {
-      constructorName = 'DoubleProperty';
+      constructorId = 'DoubleProperty';
     } else if (type.isDartCoreString) {
-      constructorName = 'StringProperty';
+      constructorId = 'StringProperty';
     } else if (isEnum(type)) {
-      constructorName = 'EnumProperty';
+      constructorId = 'EnumProperty';
+      typeArgs = [type];
     } else if (isIterable(type)) {
-      constructorName = 'IterableProperty';
+      constructorId = 'IterableProperty';
       typeArgs = (type as InterfaceType).typeArguments;
     } else if (flutter.isColor(type)) {
-      constructorName = 'ColorProperty';
+      constructorId = 'ColorProperty';
     } else if (flutter.isMatrix4(type)) {
-      constructorName = 'TransformProperty';
+      constructorId = 'TransformProperty';
     } else {
-      constructorName = 'DiagnosticsProperty';
+      constructorId = 'DiagnosticsProperty';
       if (!type.isDynamic) {
         typeArgs = [type];
       }
@@ -129,13 +135,31 @@
       @required String prefix,
       @required String builderName,
     }) {
-      builder.write("$prefix$builderName.add($constructorName");
+      builder.write("$prefix$builderName.add($constructorId");
       if (typeArgs != null) {
         builder.write('<');
         builder.writeTypes(typeArgs);
         builder.write('>');
+      } else if (type.isDynamic) {
+        TypeAnnotation declType;
+        final decl = node.thisOrAncestorOfType<VariableDeclarationList>();
+        if (decl != null) {
+          declType = decl.type;
+          // getter
+        } else if (parent is MethodDeclaration) {
+          declType = parent.returnType;
+        }
+
+        if (declType != null) {
+          final typeText = utils.getNodeText(declType);
+          if (typeText != 'dynamic') {
+            builder.write('<');
+            builder.write(utils.getNodeText(declType));
+            builder.write('>');
+          }
+        }
       }
-      builder.writeln("('${name.name}', ${name.name}));");
+      builder.writeln("$constructorName('${name.name}', ${name.name}));");
     }
 
     final classDeclaration = parent.thisOrAncestorOfType<ClassDeclaration>();
@@ -236,7 +260,7 @@
       _coverageMarker();
       return null;
     }
-    DartType type = declaredIdentifier.identifier.staticType;
+    DartType type = declaredIdentifier.declaredElement.type;
     if (type is! InterfaceType && type is! FunctionType) {
       _coverageMarker();
       return null;
@@ -1008,7 +1032,8 @@
       return null;
     }
 
-    final String relativePath = path.relative(
+    // We only write posix style paths in import directives.
+    final String relativePath = path.posix.relative(
       importUri.path,
       from: path.dirname(sourceUri.path),
     );
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 94758fd..389d63d 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -804,7 +804,7 @@
     if (parent is AssignmentExpression && target == parent.rightHandSide) {
       toType = parent.leftHandSide.staticType;
     } else if (parent is VariableDeclaration && target == parent.initializer) {
-      toType = parent.name.staticType;
+      toType = parent.declaredElement.type;
     } else {
       // TODO(brianwilkerson) Handle function arguments.
       return;
@@ -1976,12 +1976,7 @@
     bool staticModifier = false;
     ClassElement targetClassElement;
     if (target != null) {
-      // prepare target interface type
-      DartType targetType = target.staticType;
-      if (targetType is! InterfaceType) {
-        return;
-      }
-      targetClassElement = targetType.element;
+      targetClassElement = _getTargetClassElement(target);
       // maybe static
       if (target is Identifier) {
         Identifier targetIdentifier = target;
@@ -1993,11 +1988,11 @@
       }
     } else {
       targetClassElement = getEnclosingClassElement(node);
-      if (targetClassElement == null) {
-        return;
-      }
       staticModifier = _inStaticContext();
     }
+    if (targetClassElement == null) {
+      return;
+    }
     if (targetClassElement.librarySource.isInSystemLibrary) {
       return;
     }
@@ -2311,16 +2306,14 @@
       targetNode = enclosingMember.parent;
       staticModifier = _inStaticContext();
     } else {
-      // prepare target interface type
-      DartType targetType = target.staticType;
-      if (targetType is! InterfaceType) {
-        return;
-      }
-      ClassElement targetClassElement = targetType.element as ClassElement;
-      if (targetClassElement.librarySource.isInSystemLibrary) {
+      var targetClassElement = _getTargetClassElement(target);
+      if (targetClassElement == null) {
         return;
       }
       targetElement = targetClassElement;
+      if (targetClassElement.librarySource.isInSystemLibrary) {
+        return;
+      }
       // prepare target ClassDeclaration
       targetNode = await _getClassDeclaration(targetClassElement);
       if (targetNode == null) {
@@ -4182,9 +4175,8 @@
           target.staticElement is ExtensionElement) {
         _updateFinderWithExtensionMembers(finder, target.staticElement);
       } else {
-        DartType type = target.staticType;
-        if (type is InterfaceType) {
-          ClassElement classElement = type.element;
+        var classElement = _getTargetClassElement(target);
+        if (classElement != null) {
           _updateFinderWithClassMembers(finder, classElement);
         }
       }
@@ -4940,6 +4932,19 @@
     }
   }
 
+  static ClassElement _getTargetClassElement(Expression target) {
+    var type = target.staticType;
+    if (type is InterfaceType) {
+      return type.element;
+    } else if (target is Identifier) {
+      var element = target.staticElement;
+      if (element is ClassElement) {
+        return element;
+      }
+    }
+    return null;
+  }
+
   static bool _isNameOfType(String name) {
     if (name.isEmpty) {
       return false;
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index ad60430..99d4666 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -2525,14 +2525,14 @@
   void applyChangesToContext(Folder contextFolder, ChangeSet changeSet) {
     AnalysisDriver driver = driverMap[contextFolder.path];
     if (driver != null) {
-      changeSet.addedSources.forEach((source) {
-        driver.addFile(source.fullName);
+      changeSet.addedFiles.forEach((source) {
+        driver.addFile(source);
       });
-      changeSet.changedSources.forEach((source) {
-        driver.changeFile(source.fullName);
+      changeSet.changedFiles.forEach((source) {
+        driver.changeFile(source);
       });
-      changeSet.removedSources.forEach((source) {
-        driver.removeFile(source.fullName);
+      changeSet.removedFiles.forEach((source) {
+        driver.removeFile(source);
       });
     }
   }
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 28a5b6e..cbd5e65 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -1298,4 +1298,3 @@
     return new Future.value();
   }
 }
-
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 7056d15..87fed8c 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
@@ -37,14 +37,14 @@
   }
 
   test_outputContainsEachPath() async {
-    LibraryInfo info = LibraryInfo([
+    LibraryInfo info = LibraryInfo({
       unit('/package/lib/a.dart', 'int? a = null;',
           regions: [RegionInfo(3, 1, 'null was assigned', [])]),
       unit('/package/lib/part1.dart', 'int? b = null;',
           regions: [RegionInfo(3, 1, 'null was assigned', [])]),
       unit('/package/lib/part2.dart', 'int? c = null;',
           regions: [RegionInfo(3, 1, 'null was assigned', [])]),
-    ]);
+    });
     List<String> contents = renderLibrary(info);
     expect(contents[0], contains(resourceProvider.convertPath('lib/a.dart')));
     expect(
@@ -54,37 +54,37 @@
   }
 
   test_outputContainsEscapedHtml() async {
-    LibraryInfo info = LibraryInfo([
+    LibraryInfo info = LibraryInfo({
       unit('/package/lib/a.dart', 'List<String>? a = null;',
           regions: [RegionInfo(12, 1, 'null was assigned', [])]),
-    ]);
+    });
     String output = renderLibrary(info)[0];
     expect(
         output,
         contains('List&lt;String&gt;<span class="region">?'
-            '<span class="tooltip">null was assigned<ul></ul></span></span> '
-            'a = null;'));
+            '<span class="tooltip"><p>null was assigned</p>'
+            '</span></span> a = null;'));
   }
 
   test_outputContainsEscapedHtml_ampersand() async {
-    LibraryInfo info = LibraryInfo([
+    LibraryInfo info = LibraryInfo({
       unit('/package/lib/a.dart', 'bool a = true && false;', regions: []),
-    ]);
+    });
     String output = renderLibrary(info)[0];
     expect(output, contains('bool a = true &amp;&amp; false;'));
   }
 
   test_outputContainsModifiedAndUnmodifiedRegions() async {
-    LibraryInfo info = LibraryInfo([
+    LibraryInfo info = LibraryInfo({
       unit('/package/lib/a.dart', 'int? a = null;',
           regions: [RegionInfo(3, 1, 'null was assigned', [])]),
-    ]);
+    });
     String output = renderLibrary(info)[0];
     expect(
         output,
         contains('int<span class="region">?'
-            '<span class="tooltip">null was assigned<ul></ul></span></span> '
-            'a = null;'));
+            '<span class="tooltip"><p>null was assigned</p>'
+            '</span></span> a = null;'));
   }
 
   UnitInfo unit(String path, String content, {List<RegionInfo> regions}) {
diff --git a/pkg/analysis_server/test/services/completion/dart/completion_ranking_internal_test.dart b/pkg/analysis_server/test/services/completion/dart/completion_ranking_internal_test.dart
index ad33cdb..77d58d3 100644
--- a/pkg/analysis_server/test/services/completion/dart/completion_ranking_internal_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/completion_ranking_internal_test.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:analysis_server/src/protocol_server.dart';
 import 'package:analysis_server/src/provisional/completion/dart/completion_dart.dart';
 import 'package:analysis_server/src/services/completion/dart/completion_ranking_internal.dart';
 import 'package:analyzer/dart/ast/ast.dart';
@@ -86,7 +87,7 @@
     when(token.offset).thenReturn(4);
     when(token.length).thenReturn(1);
     when(token.lexeme).thenReturn(')');
-    expect(isStopToken(token, 5), equals(false));
+    expect(isStopToken(token, 5), equals(true));
   });
 
   test('isStopToken alphabetic', () {
@@ -95,7 +96,7 @@
     when(token.offset).thenReturn(2);
     when(token.length).thenReturn(3);
     when(token.lexeme).thenReturn('foo');
-    expect(isStopToken(token, 5), equals(true));
+    expect(isStopToken(token, 5), equals(false));
   });
 
   test('isStringLiteral null', () {
@@ -194,6 +195,34 @@
     expect(constructQuery(request, 100), equals(['class', 'Animal']));
   });
 
+  test('constructQuery cursor over paren', () {
+    final start = MockToken();
+    when(start.isSynthetic).thenReturn(true);
+    when(start.isEof).thenReturn(true);
+    final one = MockToken();
+    when(one.lexeme).thenReturn('main');
+    when(one.offset).thenReturn(0);
+    when(one.length).thenReturn(4);
+    when(one.isSynthetic).thenReturn(false);
+    when(one.isEof).thenReturn(false);
+    when(one.type).thenReturn(TokenType.IDENTIFIER);
+    final two = MockToken();
+    when(two.lexeme).thenReturn('(');
+    when(two.offset).thenReturn(5);
+    when(two.length).thenReturn(1);
+    when(two.isSynthetic).thenReturn(false);
+    when(one.previous).thenReturn(start);
+    when(two.previous).thenReturn(one);
+    when(two.type).thenReturn(TokenType.OPEN_PAREN);
+    when(two.isEof).thenReturn(false);
+    final request = MockCompletionRequest();
+    final target = MockCompletionTarget();
+    when(request.offset).thenReturn(6);
+    when(request.target).thenReturn(target);
+    when(target.entity).thenReturn(two);
+    expect(constructQuery(request, 50), equals(['main', '(']));
+  });
+
   test('elementNameFromRelevanceTag', () {
     final tag =
         'package::flutter/src/widgets/preferred_size.dart::::PreferredSizeWidget';
@@ -212,4 +241,29 @@
     expect(result[2].key, equals('qu\'ux'));
     expect(result, hasLength(3));
   });
+
+  test('testNamedArgument', () {
+    expect(testNamedArgument([]), equals(false));
+    expect(testNamedArgument(null), equals(false));
+    expect(
+        testNamedArgument([
+          CompletionSuggestion(CompletionSuggestionKind.NAMED_ARGUMENT, 1,
+              'title: ,', 8, 0, false, false)
+        ]),
+        equals(true));
+    expect(
+        testNamedArgument([
+          CompletionSuggestion(
+              CompletionSuggestionKind.IDENTIFIER, 1, 'foo', 3, 0, false, false)
+        ]),
+        equals(false));
+    expect(
+        testNamedArgument([
+          CompletionSuggestion(CompletionSuggestionKind.NAMED_ARGUMENT, 1,
+              'title: ,', 8, 0, false, false),
+          CompletionSuggestion(CompletionSuggestionKind.IDENTIFIER, 1, 'foo', 3,
+              0, false, false),
+        ]),
+        equals(true));
+  });
 }
diff --git a/pkg/analysis_server/test/services/completion/dart/completion_ranking_test.dart b/pkg/analysis_server/test/services/completion/dart/completion_ranking_test.dart
index ec65acd..f975eb1 100644
--- a/pkg/analysis_server/test/services/completion/dart/completion_ranking_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/completion_ranking_test.dart
@@ -20,7 +20,7 @@
     final tokens =
         tokenize('if (list == null) { return; } for (final i = 0; i < list.');
     final response = await ranking.makeRequest('predict', tokens);
-    expect(response['data']['length'], greaterThan(0.95));
+    expect(response['data']['length'], greaterThan(0.85));
   });
 }
 
diff --git a/pkg/analysis_server/test/services/completion/dart/language_model_test.dart b/pkg/analysis_server/test/services/completion/dart/language_model_test.dart
index 2163e7b..d28165d 100644
--- a/pkg/analysis_server/test/services/completion/dart/language_model_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/language_model_test.dart
@@ -11,7 +11,7 @@
 
 final directory = path.join(File.fromUri(Platform.script).parent.path, '..',
     '..', '..', '..', 'language_model', 'lexeme');
-const expectedLookback = 100;
+const expectedLookback = 50;
 
 void main() {
   if (sizeOf<IntPtr>() == 4) {
@@ -47,7 +47,7 @@
     final suggestions = model.predictWithScores(tokens);
     final best = suggestions.entries.first;
     expect(best.key, 'length');
-    expect(best.value, greaterThan(0.8));
+    expect(best.value, greaterThan(0.85));
     expect(suggestions, hasLength(model.completions));
   });
 
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 7ec4aee..da8dc4c 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
@@ -5018,4 +5018,14 @@
     // Suggested by LibraryPrefixContributor
     assertNotSuggested('x');
   }
+
+  test_extensionDeclaration_unnamed() async {
+    addTestSource('''
+extension on String {
+  void something() => this.^
+}
+''');
+    await computeSuggestions();
+    assertNoSuggestions();
+  }
 }
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 11eb5eb..79c7091 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
@@ -15,6 +15,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(TypeMemberContributorTest);
+    defineReflectiveTests(TypeMemberContributorWithExtensionMethodsTest);
   });
 }
 
@@ -4069,3 +4070,31 @@
     assertNotSuggested('e');
   }
 }
+
+@reflectiveTest
+class TypeMemberContributorWithExtensionMethodsTest
+    extends DartCompletionContributorTest {
+  @override
+  DartCompletionContributor createContributor() {
+    return new TypeMemberContributor();
+  }
+
+  void setUp() {
+    createAnalysisOptionsFile(experiments: ['extension-methods']);
+    super.setUp();
+  }
+
+  test_extensionOverride() async {
+    addTestSource('''
+extension E on int {
+  int get foo => 0;
+}
+
+void f() {
+  E(1).^
+}
+''');
+    await computeSuggestions();
+    assertNotSuggested('toString');
+  }
+}
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 e9f2f1b..bc9a5e5 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
@@ -28,6 +28,29 @@
   /// not yet completed.
   List<UnitInfo> infos;
 
+  /// Assert various properties of the given [detail].
+  void assertDetail({@required RegionDetail detail, int offset, int length}) {
+    if (offset != null) {
+      expect(detail.target.offset, offset);
+    }
+    if (length != null) {
+      expect(detail.target.length, length);
+    }
+  }
+
+  /// Assert that some target in [targets] has various properties.
+  void assertInTargets(
+      {@required Iterable<NavigationTarget> targets, int offset, int length}) {
+    String failureReasons = [
+      if (offset != null) 'offset: $offset',
+      if (length != null) 'length: $length',
+    ].join(' and ');
+    expect(targets.any((t) {
+      return (offset == null || offset == t.offset) &&
+          (length == null || length == t.length);
+    }), isTrue, reason: 'Expected one of $targets to contain $failureReasons');
+  }
+
   /// Assert various properties of the given [region]. If an [offset] is
   /// provided but no [length] is provided, a default length of `1` will be
   /// used.
@@ -69,7 +92,53 @@
     // Build the migration info.
     InstrumentationInformation info = instrumentationListener.data;
     InfoBuilder builder = InfoBuilder(info, listener);
-    infos = await builder.explainMigration();
+    infos = (await builder.explainMigration()).toList();
+  }
+
+  test_asExpression() async {
+    addTestFile('''
+void f([num a]) {
+  int b = a as int;
+}
+''');
+    await buildInfo();
+    UnitInfo unit = infos[0];
+    expect(unit.content, '''
+void f([num? a]) {
+  int? b = a as int?;
+}
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(3));
+    assertRegion(region: regions[0], offset: 11);
+    assertRegion(
+        region: regions[1],
+        offset: 24,
+        details: ["This variable is initialized to a nullable value"]);
+    assertRegion(
+        region: regions[2],
+        offset: 38,
+        details: ["The value of the expression is nullable"]);
+  }
+
+  test_expressionFunctionReturnTarget() async {
+    addTestFile('''
+String g() => 1 == 2 ? "Hello" : null;
+''');
+    await buildInfo();
+    UnitInfo unit = infos[0];
+    expect(unit.content, '''
+String? g() => 1 == 2 ? "Hello" : null;
+''');
+    assertInTargets(targets: unit.targets, offset: 7, length: 1); // "g"
+    assertInTargets(targets: unit.targets, offset: 11, length: 2); // "=>"
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(1));
+    assertRegion(
+        region: regions[0],
+        offset: 6,
+        details: ["This function returns a nullable value"]);
+    assertDetail(detail: regions[0].details[0], offset: 11, length: 2);
   }
 
   test_field_fieldFormalInitializer_optional() async {
@@ -242,7 +311,45 @@
         details: ["A nullable value is explicitly passed as an argument"]);
   }
 
-  test_parameter_fromOverriden() async {
+  test_parameter_fromOverriden_explicit() async {
+    addTestFile('''
+class A {
+  void m(int p) {}
+}
+class B extends A {
+  void m(Object p) {}
+}
+void f(A a) {
+  a.m(null);
+}
+''');
+    await buildInfo();
+    expect(infos, hasLength(1));
+    UnitInfo unit = infos[0];
+    expect(unit.path, testFile);
+    expect(unit.content, '''
+class A {
+  void m(int? p) {}
+}
+class B extends A {
+  void m(Object? p) {}
+}
+void f(A a) {
+  a.m(null);
+}
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(2));
+    assertRegion(
+        region: regions[0],
+        offset: 22,
+        details: ["An explicit 'null' is passed as an argument"]);
+    assertRegion(region: regions[1], offset: 67, details: [
+      "The corresponding parameter in the overridden method is nullable"
+    ]);
+  }
+
+  test_parameter_fromOverriden_implicit() async {
     addTestFile('''
 class A {
   void m(p) {}
@@ -357,6 +464,86 @@
         details: ["This parameter has an implicit default value of 'null'"]);
   }
 
+  @failingTest
+  test_return_fromOverriden() async {
+    addTestFile('''
+abstract class A {
+  String m();
+}
+class B implements A {
+  String m() => 1 == 2 ? "Hello" : null;
+}
+''');
+    await buildInfo();
+    expect(infos, hasLength(1));
+    UnitInfo unit = infos[0];
+    expect(unit.path, testFile);
+    expect(unit.content, '''
+abstract class A {
+  String? m();
+}
+class B implements A {
+  String? m() => 1 == 2 ? "Hello" : null;
+}
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(2));
+    assertRegion(
+        region: regions[0],
+        offset: 27,
+        details: ["An overridding method has a nullable return value"]);
+  }
+
+  test_return_multipleReturns() async {
+    addTestFile('''
+String g() {
+  int x = 1;
+  if (x == 2) return x == 3 ? "Hello" : null;
+  return "Hello";
+}
+''');
+    await buildInfo();
+    UnitInfo unit = infos[0];
+    expect(unit.content, '''
+String? g() {
+  int x = 1;
+  if (x == 2) return x == 3 ? "Hello" : null;
+  return "Hello";
+}
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(1));
+    assertRegion(
+        region: regions[0],
+        offset: 6,
+        details: ["This function returns a nullable value"]);
+    assertInTargets(targets: unit.targets, offset: 40, length: 6); // "return"
+  }
+
+  test_returnDetailTarget() async {
+    addTestFile('''
+String g() {
+  return 1 == 2 ? "Hello" : null;
+}
+''');
+    await buildInfo();
+    UnitInfo unit = infos[0];
+    expect(unit.content, '''
+String? g() {
+  return 1 == 2 ? "Hello" : null;
+}
+''');
+    assertInTargets(targets: unit.targets, offset: 7, length: 1); // "g"
+    assertInTargets(targets: unit.targets, offset: 15, length: 6); // "return"
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(1));
+    assertRegion(
+        region: regions[0],
+        offset: 6,
+        details: ["This function returns a nullable value"]);
+    assertDetail(detail: regions[0].details[0], offset: 15, length: 6);
+  }
+
   test_returnType_function_expression() async {
     addTestFile('''
 int _f = null;
diff --git a/pkg/analysis_server/test/src/services/correction/assist/add_diagnostic_property_reference_test.dart b/pkg/analysis_server/test/src/services/correction/assist/add_diagnostic_property_reference_test.dart
new file mode 100644
index 0000000..9a533a0
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/assist/add_diagnostic_property_reference_test.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.
+
+import 'package:analysis_server/src/services/correction/assist.dart';
+import 'package:analyzer_plugin/utilities/assist/assist.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'assist_processor.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(AddDiagnosticPropertyReferenceTest);
+  });
+}
+
+@reflectiveTest
+class AddDiagnosticPropertyReferenceTest extends AssistProcessorTest {
+  @override
+  AssistKind get kind => DartAssistKind.ADD_DIAGNOSTIC_PROPERTY_REFERENCE;
+
+  /// Full coverage in fix/add_diagnostic_property_reference_test.dart
+  test_boolField_debugFillProperties() async {
+    verifyNoTestUnitErrors = false;
+    await resolveTestUnit('''
+class W extends Widget {
+  bool /*caret*/property;
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+  }
+}
+''');
+    await assertHasAssist('''
+class W extends Widget {
+  bool property;
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+    properties.add(DiagnosticsProperty<bool>('property', property));
+  }
+}
+''');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/assist/test_all.dart b/pkg/analysis_server/test/src/services/correction/assist/test_all.dart
index 5580921..f9a729b 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/test_all.dart
@@ -4,6 +4,7 @@
 
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import 'add_diagnostic_property_reference_test.dart' as add_diagnostic_property;
 import 'add_not_null_assert.dart' as add_not_null_assert;
 import 'add_type_annotation_test.dart' as add_type_annotation;
 import 'assign_to_local_variable_test.dart' as assign_to_local_variable;
@@ -83,6 +84,7 @@
 
 main() {
   defineReflectiveSuite(() {
+    add_diagnostic_property.main();
     add_not_null_assert.main();
     add_type_annotation.main();
     assign_to_local_variable.main();
diff --git a/pkg/analysis_server/test/src/services/correction/fix/add_diagnostic_property_reference_test.dart b/pkg/analysis_server/test/src/services/correction/fix/add_diagnostic_property_reference_test.dart
index 4cf256e..f64eff8 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/add_diagnostic_property_reference_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/add_diagnostic_property_reference_test.dart
@@ -186,9 +186,9 @@
 
   test_enumField_debugFillProperties() async {
     await resolveTestUnit('''
-enum foo {bar}
+enum Foo {bar}
 class A extends Widget {
-  foo /*LINT*/field;
+  Foo /*LINT*/field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
     super.debugFillProperties(properties);
@@ -196,13 +196,44 @@
 }
 ''');
     await assertHasFix('''
-enum foo {bar}
+enum Foo {bar}
 class A extends Widget {
-  foo /*LINT*/field;
+  Foo /*LINT*/field;
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
     super.debugFillProperties(properties);
-    properties.add(EnumProperty('field', field));
+    properties.add(EnumProperty<Foo>('field', field));
+  }
+}
+''');
+  }
+
+  test_functionField_debugFillProperties() async {
+    addFlutterPackage();
+    await resolveTestUnit('''
+import 'package:flutter/material.dart';
+
+typedef ValueChanged<T> = void Function(T value);
+
+class A extends Widget {
+  ValueChanged<double> /*LINT*/onChanged;
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+  }
+}
+''');
+    await assertHasFix('''
+import 'package:flutter/material.dart';
+
+typedef ValueChanged<T> = void Function(T value);
+
+class A extends Widget {
+  ValueChanged<double> /*LINT*/onChanged;
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+    properties.add(ObjectFlagProperty<ValueChanged<double>>.has('onChanged', onChanged));
   }
 }
 ''');
@@ -361,6 +392,75 @@
 ''');
   }
 
+  test_typeOutOfScopeField_debugFillProperties() async {
+    await resolveTestUnit('''
+class A extends Widget {
+  ClassNotInScope<bool> /*LINT*/onChanged;
+
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+  }
+}
+''');
+    await assertHasFix('''
+class A extends Widget {
+  ClassNotInScope<bool> /*LINT*/onChanged;
+
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+    properties.add(DiagnosticsProperty<ClassNotInScope<bool>>('onChanged', onChanged));
+  }
+}
+''');
+  }
+
+  test_typeOutOfScopeGetter_debugFillProperties() async {
+    await resolveTestUnit('''
+class A extends Widget {
+  ClassNotInScope<bool> get /*LINT*/onChanged => null;
+
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+  }
+}
+''');
+    await assertHasFix('''
+class A extends Widget {
+  ClassNotInScope<bool> get /*LINT*/onChanged => null;
+
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+    properties.add(DiagnosticsProperty<ClassNotInScope<bool>>('onChanged', onChanged));
+  }
+}
+''');
+  }
+
+  test_varField_debugFillProperties() async {
+    await resolveTestUnit('''
+class A extends Widget {
+  var /*LINT*/field;
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+  }
+}
+''');
+    await assertHasFix('''
+class A extends Widget {
+  var /*LINT*/field;
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+    properties.add(DiagnosticsProperty('field', field));
+  }
+}
+''');
+  }
+
   // todo (pq): consider a test for a body w/ no CR
-  // todo (pq): support for DiagnosticsProperty for any T that doesn't match one of the other cases
 }
diff --git a/pkg/analysis_server/tool/spec/codegen_analysis_server.dart b/pkg/analysis_server/tool/spec/codegen_analysis_server.dart
index d81e94c..87c577c 100644
--- a/pkg/analysis_server/tool/spec/codegen_analysis_server.dart
+++ b/pkg/analysis_server/tool/spec/codegen_analysis_server.dart
@@ -17,13 +17,6 @@
 class CodegenAnalysisServer extends CodegenJavaVisitor {
   CodegenAnalysisServer(Api api) : super(api);
 
-  /**
-   * Get the name of the consumer class for responses to this request.
-   */
-  String consumerName(Request request) {
-    return camelJoin([request.method, 'consumer'], doCapitalize: true);
-  }
-
   @override
   void visitApi() {
     outputHeader(javaStyle: true);
diff --git a/pkg/analysis_server/tool/spec/codegen_java.dart b/pkg/analysis_server/tool/spec/codegen_java.dart
index 1e64953..a9b5afa 100644
--- a/pkg/analysis_server/tool/spec/codegen_java.dart
+++ b/pkg/analysis_server/tool/spec/codegen_java.dart
@@ -72,6 +72,13 @@
         super(api);
 
   /**
+   * Get the name of the consumer class for responses to this request.
+   */
+  String consumerName(Request request) {
+    return camelJoin([request.method, 'consumer'], doCapitalize: true);
+  }
+
+  /**
    * Create a constructor, using [callback] to create its contents.
    */
   void constructor(String name, void callback()) {
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index a7f3aef..821ed3e 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -6,6 +6,7 @@
 
 import 'package:analyzer/diagnostic/diagnostic.dart';
 import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/error/ffi_code.dart';
 import 'package:analyzer/src/dart/scanner/scanner.dart' show ScannerErrorCode;
 import 'package:analyzer/src/diagnostic/diagnostic.dart';
 import 'package:analyzer/src/error/codes.dart';
@@ -26,11 +27,12 @@
   // following command from the root of the analyzer package:
   //
   // > cat
-  //       lib/src/analysis_options/error/option_codes.dart';
-  //       lib/src/dart/error/hint_codes.dart';
-  //       lib/src/dart/error/lint_codes.dart';
-  //       lib/src/dart/error/todo_codes.dart';
-  //       lib/src/html/error/html_codes.dart';
+  //       lib/src/analysis_options/error/option_codes.dart
+  //       lib/src/dart/error/ffi_code.dart
+  //       lib/src/dart/error/hint_codes.dart
+  //       lib/src/dart/error/lint_codes.dart
+  //       lib/src/dart/error/todo_codes.dart
+  //       lib/src/html/error/html_codes.dart
   //       lib/src/dart/error/syntactic_errors.dart
   //       lib/src/error/codes.dart
   //       ../front_end/lib/src/scanner/errors.dart |
@@ -196,6 +198,7 @@
   CompileTimeErrorCode.INVALID_TYPE_ARGUMENT_IN_CONST_SET,
   CompileTimeErrorCode.INVALID_URI,
   CompileTimeErrorCode.INVALID_USE_OF_COVARIANT,
+  // ignore: deprecated_member_use_from_same_package
   CompileTimeErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION,
   CompileTimeErrorCode.INVOCATION_OF_EXTENSION_WITHOUT_CALL,
   CompileTimeErrorCode.LABEL_IN_OUTER_SCOPE,
@@ -318,6 +321,28 @@
   CompileTimeErrorCode.WRONG_TYPE_PARAMETER_VARIANCE_IN_SUPERINTERFACE,
   CompileTimeErrorCode.YIELD_EACH_IN_NON_GENERATOR,
   CompileTimeErrorCode.YIELD_IN_NON_GENERATOR,
+  FfiCode.ANNOTATION_ON_POINTER_FIELD,
+  FfiCode.EXTRA_ANNOTATION_ON_STRUCT_FIELD,
+  FfiCode.FIELD_IN_STRUCT_WITH_INITIALIZER,
+  FfiCode.FIELD_INITIALIZER_IN_STRUCT,
+  FfiCode.GENERIC_STRUCT_SUBCLASS,
+  FfiCode.INVALID_EXCEPTION_VALUE,
+  FfiCode.INVALID_FIELD_TYPE_IN_STRUCT,
+  FfiCode.MISMATCHED_ANNOTATION_ON_STRUCT_FIELD,
+  FfiCode.MISSING_ANNOTATION_ON_STRUCT_FIELD,
+  FfiCode.MISSING_EXCEPTION_VALUE,
+  FfiCode.MISSING_FIELD_TYPE_IN_STRUCT,
+  FfiCode.MUST_BE_A_NATIVE_FUNCTION_TYPE,
+  FfiCode.MUST_BE_A_SUBTYPE,
+  FfiCode.NON_CONSTANT_TYPE_ARGUMENT,
+  FfiCode.NON_CONSTANT_TYPE_ARGUMENT_TO_POINTER,
+  FfiCode.NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER,
+  FfiCode.SUBTYPE_OF_FFI_CLASS_IN_EXTENDS,
+  FfiCode.SUBTYPE_OF_FFI_CLASS_IN_IMPLEMENTS,
+  FfiCode.SUBTYPE_OF_FFI_CLASS_IN_WITH,
+  FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_EXTENDS,
+  FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_IMPLEMENTS,
+  FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_WITH,
   HintCode.CAN_BE_NULL_AFTER_NULL_AWARE,
   HintCode.DEAD_CODE,
   HintCode.DEAD_CODE_CATCH_FOLLOWING_CATCH,
@@ -522,6 +547,7 @@
   ParserErrorCode.INVALID_STAR_AFTER_ASYNC,
   ParserErrorCode.INVALID_SYNC,
   ParserErrorCode.INVALID_UNICODE_ESCAPE,
+  ParserErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION,
   ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST,
   ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER,
   ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR,
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index 5e56d1f..be54661 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -88,11 +88,6 @@
     return _typeSystem ??= Dart2TypeSystem(typeProvider);
   }
 
-  @override
-  void applyChanges(ChangeSet changeSet) {
-    throw UnimplementedError();
-  }
-
   /**
    * Create an analysis cache based on the given source [factory].
    */
diff --git a/pkg/analyzer/lib/src/dart/analysis/dependency/reference_collector.dart b/pkg/analyzer/lib/src/dart/analysis/dependency/reference_collector.dart
index 01b5ac3..98c9a8a 100644
--- a/pkg/analyzer/lib/src/dart/analysis/dependency/reference_collector.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/dependency/reference_collector.dart
@@ -164,7 +164,17 @@
     return null;
   }
 
-  void _recordClassMemberReference(DartType targetType, String name) {
+  void _recordClassMemberReference(
+      {Expression target, DartType targetType, String name}) {
+    if (target is Identifier) {
+      var element = target.staticElement;
+      if (element is ClassElement) {
+        _memberReferences.add(element, name);
+        return;
+      }
+    }
+    targetType ??= target.staticType;
+
     if (targetType is InterfaceType) {
       _memberReferences.add(targetType.element, name);
     }
@@ -203,8 +213,8 @@
         assignmentType != TokenType.QUESTION_QUESTION_EQ) {
       var operatorType = operatorFromCompoundAssignment(assignmentType);
       _recordClassMemberReference(
-        node.leftHandSide.staticType,
-        operatorType.lexeme,
+        targetType: node.leftHandSide.staticType,
+        name: operatorType.lexeme,
       );
     }
   }
@@ -216,7 +226,10 @@
       _superReferences.add(operatorName);
     } else {
       _visitExpression(leftOperand);
-      _recordClassMemberReference(leftOperand.staticType, operatorName);
+      _recordClassMemberReference(
+        targetType: leftOperand.staticType,
+        name: operatorName,
+      );
     }
     _visitExpression(node.rightOperand);
   }
@@ -263,9 +276,9 @@
     _visitTypeAnnotation(type);
 
     if (name != null) {
-      _recordClassMemberReference(type.type, name.name);
+      _recordClassMemberReference(targetType: type.type, name: name.name);
     } else {
-      _recordClassMemberReference(type.type, '');
+      _recordClassMemberReference(targetType: type.type, name: '');
     }
   }
 
@@ -518,10 +531,10 @@
       _visitExpression(target);
       var targetType = target.staticType;
       if (get) {
-        _recordClassMemberReference(targetType, '[]');
+        _recordClassMemberReference(targetType: targetType, name: '[]');
       }
       if (set) {
-        _recordClassMemberReference(targetType, '[]=');
+        _recordClassMemberReference(targetType: targetType, name: '[]=');
       }
     }
 
@@ -551,9 +564,7 @@
     } else {
       _visitExpression(node.target);
       _recordClassMemberReference(
-        realTarget.staticType,
-        node.methodName.name,
-      );
+          target: realTarget, name: node.methodName.name);
     }
     _visitTypeArguments(node.typeArguments);
     _visitArgumentList(node.argumentList);
@@ -564,9 +575,15 @@
 
     var operator = node.operator.type;
     if (operator == TokenType.MINUS_MINUS) {
-      _recordClassMemberReference(node.operand.staticType, '-');
+      _recordClassMemberReference(
+        targetType: node.operand.staticType,
+        name: '-',
+      );
     } else if (operator == TokenType.PLUS_PLUS) {
-      _recordClassMemberReference(node.operand.staticType, '+');
+      _recordClassMemberReference(
+        targetType: node.operand.staticType,
+        name: '+',
+      );
     } else {
       throw UnimplementedError('$operator');
     }
@@ -581,7 +598,7 @@
       importPrefix.add(node.identifier.name);
     } else {
       _visitExpression(prefix);
-      _recordClassMemberReference(prefix.staticType, node.identifier.name);
+      _recordClassMemberReference(target: prefix, name: node.identifier.name);
     }
   }
 
@@ -591,7 +608,10 @@
     var operatorName = node.operator.lexeme;
     if (operatorName == '-') operatorName = 'unary-';
 
-    _recordClassMemberReference(node.operand.staticType, operatorName);
+    _recordClassMemberReference(
+      targetType: node.operand.staticType,
+      name: operatorName,
+    );
   }
 
   void _visitPropertyAccess(PropertyAccess node,
@@ -609,10 +629,10 @@
     } else {
       _visitExpression(node.target);
       if (get) {
-        _recordClassMemberReference(realTarget.staticType, name);
+        _recordClassMemberReference(target: realTarget, name: name);
       }
       if (set) {
-        _recordClassMemberReference(realTarget.staticType, '$name=');
+        _recordClassMemberReference(target: realTarget, name: '$name=');
       }
     }
   }
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index cfb2a93..8876844 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -22,15 +22,16 @@
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
 import 'package:analyzer/src/dart/element/type_provider.dart';
-import 'package:analyzer/src/dart/resolver/ast_rewrite.dart';
 import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
 import 'package:analyzer/src/dart/resolver/legacy_type_asserter.dart';
+import 'package:analyzer/src/dart/resolver/resolution_visitor.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/error/imports_verifier.dart';
 import 'package:analyzer/src/error/inheritance_override.dart';
 import 'package:analyzer/src/generated/declaration_resolver.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error_verifier.dart';
+import 'package:analyzer/src/generated/ffi_verifier.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/hint/sdk_constraint_verifier.dart';
@@ -391,6 +392,10 @@
     ErrorVerifier errorVerifier = new ErrorVerifier(
         errorReporter, _libraryElement, _typeProvider, _inheritance, false);
     unit.accept(errorVerifier);
+
+    // Verify constraints on FFI uses. The CFE enforces these constraints as
+    // compile-time errors and so does the analyzer.
+    unit.accept(FfiVerifier(_typeSystem, errorReporter));
   }
 
   /**
@@ -624,7 +629,7 @@
 
     RecordingErrorListener errorListener = _getErrorListener(file);
 
-    CompilationUnitElement unitElement = unit.declaredElement;
+    CompilationUnitElementImpl unitElement = unit.declaredElement;
 
     // TODO(scheglov) Hack: set types for top-level variables
     // Otherwise TypeResolverVisitor will set declared types, and because we
@@ -637,21 +642,15 @@
       }
     }
 
-    timerLibraryAnalyzerSplicer.start();
-    new DeclarationResolver().resolve(unit, unitElement);
-    timerLibraryAnalyzerSplicer.stop();
-
-    unit.accept(new AstRewriteVisitor(_context.typeSystem, _libraryElement,
-        source, _typeProvider, errorListener,
-        nameScope: _libraryScope));
-
-    new TypeParameterBoundsResolver(_context.typeSystem, _libraryElement,
-            source, errorListener, unit.featureSet)
-        .resolveTypeBounds(unit);
-
-    unit.accept(new TypeResolverVisitor(
-        _libraryElement, source, _typeProvider, errorListener,
-        featureSet: unit.featureSet));
+    unit.accept(
+      ResolutionVisitor(
+        unitElement: unitElement,
+        errorListener: errorListener,
+        featureSet: unit.featureSet,
+        nameScope: _libraryScope,
+        elementWalker: ElementWalker.forCompilationUnit(unitElement),
+      ),
+    );
 
     unit.accept(new VariableResolverVisitor(
         _libraryElement, source, _typeProvider, errorListener,
@@ -672,7 +671,7 @@
     FlowAnalysisHelper flowAnalysisHelper;
     if (unit.featureSet.isEnabled(Feature.non_nullable)) {
       flowAnalysisHelper =
-          FlowAnalysisHelper(_context.typeSystem, unit, _testingData != null);
+          FlowAnalysisHelper(_context.typeSystem, _testingData != null);
       _testingData?.recordFlowAnalysisResult(
           file.uri, flowAnalysisHelper.result);
     }
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index 42f7ab6..4e70221 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -862,19 +862,6 @@
       return true;
     }
     var objType = obj.type;
-    if (objType.isDartCoreInt && type.isDartCoreDouble) {
-      // Work around dartbug.com/35993 by allowing `int` to be used in a place
-      // where `double` is expected.
-      //
-      // Note that this is not technically correct, because it allows code like
-      // this:
-      //   const Object x = 1;
-      //   const double y = x;
-      //
-      // TODO(paulberry): remove this workaround once dartbug.com/33441 is
-      // fixed.
-      return true;
-    }
     return typeSystem.isSubtypeOf(objType, type);
   }
 
diff --git a/pkg/analyzer/lib/src/dart/constant/utilities.dart b/pkg/analyzer/lib/src/dart/constant/utilities.dart
index ef993d0..e792f72 100644
--- a/pkg/analyzer/lib/src/dart/constant/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/constant/utilities.dart
@@ -13,17 +13,12 @@
 import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/dart/constant/evaluation.dart';
 import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/handle.dart'
-    show ConstructorElementHandle;
 import 'package:analyzer/src/dart/element/member.dart';
 
 ConstructorElementImpl getConstructorImpl(ConstructorElement constructor) {
   while (constructor is ConstructorMember) {
     constructor = (constructor as ConstructorMember).baseElement;
   }
-  if (constructor is ConstructorElementHandle) {
-    constructor = (constructor as ConstructorElementHandle).actualElement;
-  }
   return constructor;
 }
 
diff --git a/pkg/analyzer/lib/src/dart/element/builder.dart b/pkg/analyzer/lib/src/dart/element/builder.dart
index 4565244..424d5dc 100644
--- a/pkg/analyzer/lib/src/dart/element/builder.dart
+++ b/pkg/analyzer/lib/src/dart/element/builder.dart
@@ -345,7 +345,6 @@
     if (body.isGenerator) {
       element.generator = true;
     }
-    element.type = new FunctionTypeImpl(element);
     element.hasImplicitReturnType = true;
     _currentHolder.addFunction(element);
     (node as FunctionExpressionImpl).declaredElement = element;
@@ -1278,7 +1277,6 @@
     if (enclosingBlock != null) {
       element.setVisibleRange(enclosingBlock.offset, enclosingBlock.length);
     }
-    element.type = new FunctionTypeImpl(element);
     element.hasImplicitReturnType = true;
     _currentHolder.addFunction(element);
     (node as FunctionExpressionImpl).declaredElement = element;
@@ -1384,7 +1382,6 @@
       initializer.encloseElements(holder.localVariables);
       initializer.parameters = holder.parameters;
       initializer.isSynthetic = true;
-      initializer.type = new FunctionTypeImpl(initializer);
       parameter.initializer = initializer;
       parameter.defaultValueCode = defaultValue.toSource();
       holder.validate();
@@ -1407,7 +1404,6 @@
       initializerElement.encloseElements(holder.labels);
       initializerElement.encloseElements(holder.localVariables);
       initializerElement.isSynthetic = true;
-      initializerElement.type = new FunctionTypeImpl(initializerElement);
       variable.initializer = initializerElement;
       holder.validate();
     }
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index cb5fd11..d405d8a 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -17,7 +17,6 @@
 import 'package:analyzer/src/dart/constant/compute.dart';
 import 'package:analyzer/src/dart/constant/evaluation.dart';
 import 'package:analyzer/src/dart/constant/value.dart';
-import 'package:analyzer/src/dart/element/handle.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_algebra.dart';
 import 'package:analyzer/src/generated/constant.dart' show EvaluationResultImpl;
@@ -113,21 +112,17 @@
   @override
   InterfaceType get thisType {
     if (_thisType == null) {
-      // TODO(scheglov) `library` is null in low-level unit tests
-      var nullabilitySuffix = library?.isNonNullableByDefault == true
-          ? NullabilitySuffix.none
-          : NullabilitySuffix.star;
       List<DartType> typeArguments;
       if (typeParameters.isNotEmpty) {
         typeArguments = typeParameters.map<DartType>((t) {
-          return t.instantiate(nullabilitySuffix: nullabilitySuffix);
+          return t.instantiate(nullabilitySuffix: _noneOrStarSuffix);
         }).toList();
       } else {
         typeArguments = const <DartType>[];
       }
       return _thisType = instantiate(
         typeArguments: typeArguments,
-        nullabilitySuffix: nullabilitySuffix,
+        nullabilitySuffix: _noneOrStarSuffix,
       );
     }
     return _thisType;
@@ -360,16 +355,6 @@
     }
   }
 
-  /// Return the [AbstractClassElementImpl] of the given [classElement].  May
-  /// throw an exception if the [AbstractClassElementImpl] cannot be provided
-  /// (should not happen though).
-  static AbstractClassElementImpl getImpl(ClassElement classElement) {
-    if (classElement is ClassElementHandle) {
-      return getImpl(classElement.actualElement);
-    }
-    return classElement as AbstractClassElementImpl;
-  }
-
   /// Return an iterable containing all of the implementations of a method with
   /// the given [methodName] that are defined in this class any any superclass
   /// of this class (but not in interfaces).
@@ -1054,9 +1039,7 @@
         visitedClasses.add(this);
       }
       try {
-        ClassElementImpl superElement =
-            AbstractClassElementImpl.getImpl(supertype.element)
-                as ClassElementImpl;
+        ClassElementImpl superElement = supertype.element;
         constructorsToForward =
             superElement._computeMixinAppConstructors(visitedClasses);
       } finally {
@@ -2235,7 +2218,16 @@
   }
 
   @override
-  DartType get returnType => enclosingElement.thisType;
+  DartType get returnType {
+    if (_returnType != null) return _returnType;
+
+    InterfaceTypeImpl classThisType = enclosingElement.thisType;
+    return _returnType = InterfaceTypeImpl.explicit(
+      classThisType.element,
+      classThisType.typeArguments,
+      nullabilitySuffix: classThisType.nullabilitySuffix,
+    );
+  }
 
   void set returnType(DartType returnType) {
     assert(false);
@@ -2243,7 +2235,14 @@
 
   @override
   FunctionType get type {
-    return _type ??= new FunctionTypeImpl(this);
+    // TODO(scheglov) Remove "element" in the breaking changes branch.
+    return _type ??= FunctionTypeImpl.synthetic(
+      returnType,
+      typeParameters,
+      parameters,
+      element: this,
+      nullabilitySuffix: _noneOrStarSuffix,
+    );
   }
 
   void set type(FunctionType type) {
@@ -3117,6 +3116,12 @@
     throw UnimplementedError();
   }
 
+  NullabilitySuffix get _noneOrStarSuffix {
+    return library?.isNonNullableByDefault == true
+        ? NullabilitySuffix.none
+        : NullabilitySuffix.star;
+  }
+
   @override
   bool operator ==(Object object) {
     if (identical(this, object)) {
@@ -3629,12 +3634,9 @@
   void createToStringMethodElement() {
     var method = new MethodElementImpl('toString', -1);
     method.isSynthetic = true;
-    if (linkedNode != null) {
-      method.returnType = context.typeProvider.stringType;
-      method.type = new FunctionTypeImpl(method);
-    }
     method.enclosingElement = this;
     if (linkedNode != null) {
+      method.returnType = context.typeProvider.stringType;
       method.reference = reference.getChild('@method').getChild('toString');
     }
     _methods = <MethodElement>[method];
@@ -3882,14 +3884,28 @@
       linkedContext.setReturnType(linkedNode, returnType);
     }
     _returnType = _checkElementOfType(returnType);
+    // We do this because of return type inference. At the moment when we
+    // create a local function element we don't know yet its return type,
+    // because we have not done static type analysis yet.
+    // It somewhere it between we access the type of this element, so it gets
+    // cached in the element. When we are done static type analysis, we then
+    // should clear this cached type to make it right.
+    // TODO(scheglov) Remove when type analysis is done in the single pass.
+    _type = null;
   }
 
   @override
   FunctionType get type {
-    if (linkedNode != null) {
-      return _type ??= new FunctionTypeImpl(this);
-    }
-    return _type;
+    if (_type != null) return _type;
+
+    // TODO(scheglov) Remove "element" in the breaking changes branch.
+    return _type = FunctionTypeImpl.synthetic(
+      returnType,
+      typeParameters,
+      parameters,
+      element: this,
+      nullabilitySuffix: _noneOrStarSuffix,
+    );
   }
 
   void set type(FunctionType type) {
@@ -4086,7 +4102,7 @@
   @override
   void appendTo(StringBuffer buffer) {
     buffer.write("export ");
-    LibraryElementImpl.getImpl(exportedLibrary).appendTo(buffer);
+    (exportedLibrary as LibraryElementImpl).appendTo(buffer);
   }
 }
 
@@ -4623,8 +4639,6 @@
     isSynthetic = true;
     this.returnType = returnType;
     this.parameters = parameters;
-
-    type = new FunctionTypeImpl(this);
   }
 
   @override
@@ -4816,8 +4830,16 @@
 
   @override
   FunctionType get type {
-    _type ??= new FunctionTypeImpl(this);
-    return _type;
+    if (_type != null) return _type;
+
+    // TODO(scheglov) Remove "element" in the breaking changes branch.
+    return _type = FunctionTypeImpl.synthetic(
+      returnType,
+      typeParameters,
+      parameters,
+      element: this,
+      nullabilitySuffix: _noneOrStarSuffix,
+    );
   }
 
   /// Set the function type defined by this function type element to the given
@@ -5366,7 +5388,7 @@
   @override
   void appendTo(StringBuffer buffer) {
     buffer.write("import ");
-    LibraryElementImpl.getImpl(importedLibrary).appendTo(buffer);
+    (importedLibrary as LibraryElementImpl).appendTo(buffer);
   }
 
   @override
@@ -5820,11 +5842,7 @@
         // expensive for libraries resynthesized from summaries, since it will
         // require fully resynthesizing all the libraries in the cycle as well
         // as any libraries they import or export.  Try to find a better way.
-        if (lib is LibraryElementHandle) {
-          return lib.actualElement;
-        } else {
-          return lib;
-        }
+        return lib;
       }
 
       void recurse(LibraryElementImpl child) {
@@ -6051,18 +6069,9 @@
     function.isSynthetic = true;
     function.enclosingElement = library;
     function.returnType = typeProvider.futureDynamicType;
-    function.type = new FunctionTypeImpl(function);
     return function;
   }
 
-  /// Return the [LibraryElementImpl] of the given [element].
-  static LibraryElementImpl getImpl(LibraryElement element) {
-    if (element is LibraryElementHandle) {
-      return getImpl(element.actualElement);
-    }
-    return element as LibraryElementImpl;
-  }
-
   static List<ImportElement> getImportsWithPrefixFromImports(
       PrefixElement prefixElement, List<ImportElement> imports) {
     int count = imports.length;
@@ -7674,7 +7683,25 @@
 
   @override
   FunctionType get type {
-    return _type ??= new FunctionTypeImpl(this);
+    if (_type != null) return _type;
+
+    // TODO(scheglov) Remove "element" in the breaking changes branch.
+    var type = FunctionTypeImpl.synthetic(
+      returnType,
+      const <TypeParameterElement>[],
+      const <ParameterElement>[],
+      element: this,
+      nullabilitySuffix: _noneOrStarSuffix,
+    );
+
+    // Don't cache, because types change during top-level inference.
+    if (enclosingElement != null &&
+        linkedContext != null &&
+        !linkedContext.isLinking) {
+      _type = type;
+    }
+
+    return type;
   }
 
   @override
@@ -7715,7 +7742,25 @@
 
   @override
   FunctionType get type {
-    return _type ??= new FunctionTypeImpl(this);
+    if (_type != null) return _type;
+
+    // TODO(scheglov) Remove "element" in the breaking changes branch.
+    var type = FunctionTypeImpl.synthetic(
+      returnType,
+      const <TypeParameterElement>[],
+      parameters,
+      element: this,
+      nullabilitySuffix: _noneOrStarSuffix,
+    );
+
+    // Don't cache, because types change during top-level inference.
+    if (enclosingElement != null &&
+        linkedContext != null &&
+        !linkedContext.isLinking) {
+      _type = type;
+    }
+
+    return type;
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/error/ffi_code.dart b/pkg/analyzer/lib/src/dart/error/ffi_code.dart
new file mode 100644
index 0000000..8cdcd7b
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/error/ffi_code.dart
@@ -0,0 +1,276 @@
+// 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/error/error.dart';
+import 'package:analyzer/src/error/analyzer_error_code.dart';
+import 'package:meta/meta.dart';
+
+/// The diagnostic codes associated with `dart:ffi`.
+class FfiCode extends AnalyzerErrorCode {
+  /**
+   * No parameters.
+   */
+  static const FfiCode ANNOTATION_ON_POINTER_FIELD = const FfiCode(
+      name: 'ANNOTATION_ON_POINTER_FIELD',
+      message:
+          "Fields in a struct class whose type is 'Pointer' should not have "
+          "any annotations.",
+      correction: "Try removing the annotation.");
+
+  /**
+   * No parameters.
+   */
+  static const FfiCode EXTRA_ANNOTATION_ON_STRUCT_FIELD = const FfiCode(
+      name: 'EXTRA_ANNOTATION_ON_STRUCT_FIELD',
+      message: "Fields in a struct class must have exactly one annotation "
+          "indicating the native type.",
+      correction: "Try removing the extra annotation.");
+
+  /**
+   * No parameters.
+   */
+  static const FfiCode FIELD_IN_STRUCT_WITH_INITIALIZER = const FfiCode(
+      name: 'FIELD_IN_STRUCT_WITH_INITIALIZER',
+      message: "Fields in subclasses of 'Struct' can't have initializers.",
+      correction: "Try removing the initializer.");
+
+  /**
+   * No parameters.
+   */
+  static const FfiCode FIELD_INITIALIZER_IN_STRUCT = const FfiCode(
+      name: 'FIELD_INITIALIZER_IN_STRUCT',
+      message: "Constructors in subclasses of 'Struct' can't have field "
+          "initializers.",
+      correction: "Try removing the field initializer.");
+
+  /**
+   * Parameters:
+   * 0: the name of the struct class
+   */
+  static const FfiCode GENERIC_STRUCT_SUBCLASS = const FfiCode(
+      name: 'GENERIC_STRUCT_SUBCLASS',
+      message: "The class '{0}' can't extend 'Struct' because it is generic.",
+      correction: "Try removing the type parameters from '{0}'.");
+
+  /**
+   * No parameters.
+   */
+  static const FfiCode INVALID_EXCEPTION_VALUE = const FfiCode(
+      name: 'INVALID_EXCEPTION_VALUE',
+      message:
+          "The method 'Pointer.fromFunction' must not have an exceptional return "
+          "value (the second argument) when the return type of the function is "
+          "either 'void' or 'Pointer'.",
+      correction: "Try removing the exceptional return value.");
+
+  /**
+   * Parameters:
+   * 0: the type of the field
+   */
+  static const FfiCode INVALID_FIELD_TYPE_IN_STRUCT = const FfiCode(
+      name: 'INVALID_FIELD_TYPE_IN_STRUCT',
+      message:
+          "Fields in struct classes can't have the type '{0}'. They can only "
+          "be declared as 'int', 'double' or 'Pointer'.",
+      correction: "Try using 'int', 'double' or 'Pointer'.");
+
+  /**
+   * No parameters.
+   */
+  static const FfiCode MISMATCHED_ANNOTATION_ON_STRUCT_FIELD = const FfiCode(
+      name: 'MISMATCHED_ANNOTATION_ON_STRUCT_FIELD',
+      message: "The annotation does not match the declared type of the field.",
+      correction: "Try using a different annotation or changing the declared "
+          "type to match.");
+
+  /**
+   * No parameters.
+   */
+  static const FfiCode MISSING_ANNOTATION_ON_STRUCT_FIELD = const FfiCode(
+      name: 'MISSING_ANNOTATION_ON_STRUCT_FIELD',
+      message:
+          "Fields in a struct class must either have the type 'Pointer' or an "
+          "annotation indicating the native type.",
+      correction: "Try adding an annotation.");
+
+  /**
+   * No parameters.
+   */
+  static const FfiCode MISSING_EXCEPTION_VALUE = const FfiCode(
+      name: 'MISSING_EXCEPTION_VALUE',
+      message:
+          "The method 'Pointer.fromFunction' must have an exceptional return "
+          "value (the second argument) when the return type of the function is "
+          "neither 'void' or 'Pointer'.",
+      correction: "Try adding an exceptional return value.");
+
+  /**
+   * Parameters:
+   * 0: the type of the field
+   */
+  static const FfiCode MISSING_FIELD_TYPE_IN_STRUCT = const FfiCode(
+      name: 'MISSING_FIELD_TYPE_IN_STRUCT',
+      message:
+          "Fields in struct classes must have an explicitly declared type of "
+          "'int', 'double' or 'Pointer'.",
+      correction: "Try using 'int', 'double' or 'Pointer'.");
+
+  /**
+   * Parameters:
+   * 0: the type that should be a valid dart:ffi native type.
+   * 1: the name of the function whose invocation depends on this relationship
+   */
+  static const FfiCode MUST_BE_A_NATIVE_FUNCTION_TYPE = const FfiCode(
+      name: 'MUST_BE_A_NATIVE_FUNCTION_TYPE',
+      message:
+          "The type '{0}' given to {1} must be a valid `dart:ffi` native function type.",
+      correction: "Try changing the type to only use members for `dart:ffi`.");
+
+  /**
+   * Parameters:
+   * 0: the type that should be a subtype
+   * 1: the supertype that the subtype is compared to
+   * 2: the name of the function whose invocation depends on this relationship
+   */
+  static const FfiCode MUST_BE_A_SUBTYPE = const FfiCode(
+      name: 'MUST_BE_A_SUBTYPE',
+      message: "The type '{0}' must be a subtype of '{1}' for '{2}'.",
+      correction: "Try changing one or both of the type arguments.");
+
+  /**
+   * Parameters:
+   * 0: the name of the function, method, or constructor having type arguments
+   */
+  static const FfiCode NON_CONSTANT_TYPE_ARGUMENT = const FfiCode(
+      name: 'NON_CONSTANT_TYPE_ARGUMENT',
+      message:
+          "The type arguments to '{0}' must be compile time constants but type "
+          "parameters are not constants.",
+      correction: "Try changing the type argument to be a constant type.");
+
+  /**
+   * No parameters.
+   */
+  static const FfiCode NON_CONSTANT_TYPE_ARGUMENT_TO_POINTER = const FfiCode(
+      name: 'NON_CONSTANT_TYPE_ARGUMENT_TO_POINTER',
+      message:
+          "The type argument for the pointer must be a compile time constant "
+          "but type parameters are not constants.",
+      correction: "Try changing the type argument to be a constant type.");
+
+  /**
+   * Parameters:
+   * 0: the type that should be a valid dart:ffi native type.
+   */
+  static const FfiCode NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER =
+      const FfiCode(
+          name: 'NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER',
+          message:
+              "The type argument for the pointer, '{0}' must be a 'NativeFunction' in "
+              "order to use 'asFunction'.",
+          correction:
+              "Try changing the type argument to be a 'NativeFunction'.");
+
+  /**
+   * Parameters:
+   * 0: the name of the subclass
+   * 1: the name of the class being extended, implemented, or mixed in
+   */
+  static const FfiCode SUBTYPE_OF_FFI_CLASS_IN_EXTENDS = const FfiCode(
+      name: 'SUBTYPE_OF_FFI_CLASS',
+      uniqueName: 'SUBTYPE_OF_FFI_CLASS_IN_EXTENDS',
+      message: "The class '{0}' can't extend '{1}'.",
+      correction: "Try extending 'Struct'.");
+
+  /**
+   * Parameters:
+   * 0: the name of the subclass
+   * 1: the name of the class being extended, implemented, or mixed in
+   */
+  static const FfiCode SUBTYPE_OF_FFI_CLASS_IN_IMPLEMENTS = const FfiCode(
+      name: 'SUBTYPE_OF_FFI_CLASS',
+      uniqueName: 'SUBTYPE_OF_FFI_CLASS_IN_IMPLEMENTS',
+      message: "The class '{0}' can't implement '{1}'.",
+      correction: "Try extending 'Struct'.");
+
+  /**
+   * Parameters:
+   * 0: the name of the subclass
+   * 1: the name of the class being extended, implemented, or mixed in
+   */
+  static const FfiCode SUBTYPE_OF_FFI_CLASS_IN_WITH = const FfiCode(
+      name: 'SUBTYPE_OF_FFI_CLASS',
+      uniqueName: 'SUBTYPE_OF_FFI_CLASS_IN_WITH',
+      message: "The class '{0}' can't mix in '{1}'.",
+      correction: "Try extending 'Struct'.");
+
+  /**
+   * Parameters:
+   * 0: the name of the subclass
+   * 1: the name of the class being extended, implemented, or mixed in
+   */
+  static const FfiCode SUBTYPE_OF_STRUCT_CLASS_IN_EXTENDS = const FfiCode(
+      name: 'SUBTYPE_OF_STRUCT_CLASS',
+      uniqueName: 'SUBTYPE_OF_STRUCT_CLASS_IN_EXTENDS',
+      message:
+          "The class '{0}' can't extend '{1}' because '{1}' is a subtype of "
+          "'Struct'.",
+      correction: "Try extending 'Struct' directly.");
+
+  /**
+   * Parameters:
+   * 0: the name of the subclass
+   * 1: the name of the class being extended, implemented, or mixed in
+   */
+  static const FfiCode SUBTYPE_OF_STRUCT_CLASS_IN_IMPLEMENTS = const FfiCode(
+      name: 'SUBTYPE_OF_STRUCT_CLASS',
+      uniqueName: 'SUBTYPE_OF_STRUCT_CLASS_IN_IMPLEMENTS',
+      message:
+          "The class '{0}' can't implement '{1}' because '{1}' is a subtype of "
+          "'Struct'.",
+      correction: "Try extending 'Struct' directly.");
+
+  /**
+   * Parameters:
+   * 0: the name of the subclass
+   * 1: the name of the class being extended, implemented, or mixed in
+   */
+  static const FfiCode SUBTYPE_OF_STRUCT_CLASS_IN_WITH = const FfiCode(
+      name: 'SUBTYPE_OF_STRUCT_CLASS',
+      uniqueName: 'SUBTYPE_OF_STRUCT_CLASS_IN_WITH',
+      message:
+          "The class '{0}' can't mix in '{1}' because '{1}' is a subtype of "
+          "'Struct'.",
+      correction: "Try extending 'Struct' directly.");
+
+  @override
+  final String uniqueName;
+
+  /// Initialize a newly created error code to have the given [name]. If
+  /// [uniqueName] is provided, then it will be used to construct the unique
+  /// name for the code, otherwise the name will be used to construct the unique
+  /// name.
+  ///
+  /// The message associated with the error will be created from the given
+  /// [message] template. The correction associated with the error will be
+  /// created from the given [correction] template.
+  ///
+  /// If [hasPublishedDocs] is `true` then a URL for the docs will be generated.
+  const FfiCode(
+      {@required String message,
+      @required String name,
+      String correction,
+      bool hasPublishedDocs,
+      String uniqueName})
+      : uniqueName =
+            uniqueName == null ? 'FfiCode.$name' : 'FfiCode.$uniqueName',
+        super.temporary(name, message,
+            correction: correction, hasPublishedDocs: hasPublishedDocs);
+
+  @override
+  ErrorSeverity get errorSeverity => type.severity;
+
+  @override
+  ErrorType get type => ErrorType.COMPILE_TIME_ERROR;
+}
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index 58cfd25..003cc29 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -1291,7 +1291,7 @@
   // ```
   static const HintCode SDK_VERSION_UI_AS_CODE = const HintCode(
       'SDK_VERSION_UI_AS_CODE',
-      "The for, if, and spread elements weren't supported until version 2.2.2, "
+      "The for, if, and spread elements weren't supported until version 2.3.0, "
           "but this code is required to be able to run on earlier versions.",
       correction: "Try updating the SDK constraints.",
       hasPublishedDocs: true);
diff --git a/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart b/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
index adf8e53..85eaf09 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
@@ -481,6 +481,38 @@
 
   static const ParserErrorCode INVALID_UNICODE_ESCAPE = _INVALID_UNICODE_ESCAPE;
 
+  /**
+   * No parameters.
+   */
+  // #### Description
+  //
+  // The analyzer produces this diagnostic when a member declared inside an
+  // extension uses the keyword `covariant` in the declaration of a parameter.
+  // Extensions aren't classes and don't have subclasses, so the keyword serves
+  // no purpose.
+  //
+  // #### Example
+  //
+  // The following code produces this diagnostic:
+  //
+  // ```dart
+  // extension E on String {
+  //   void a([!covariant!] int i) {}
+  // }
+  // ```
+  //
+  // #### Common fixes
+  //
+  // Remove the 'covariant' keyword:
+  //
+  // ```dart
+  // extension E on String {
+  //   void a(int i) {}
+  // }
+  // ```
+  static const ParserErrorCode INVALID_USE_OF_COVARIANT_IN_EXTENSION =
+      _INVALID_USE_OF_COVARIANT_IN_EXTENSION;
+
   static const ParserErrorCode LIBRARY_DIRECTIVE_NOT_FIRST =
       _LIBRARY_DIRECTIVE_NOT_FIRST;
 
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 23d0a05..f5eff9d 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
@@ -105,6 +105,7 @@
   _MIXIN_DECLARES_CONSTRUCTOR,
   _NULL_AWARE_CASCADE_OUT_OF_ORDER,
   _MULTIPLE_VARIANCE_MODIFIERS,
+  _INVALID_USE_OF_COVARIANT_IN_EXTENSION,
 ];
 
 const ParserErrorCode _ABSTRACT_CLASS_MEMBER = const ParserErrorCode(
@@ -398,6 +399,11 @@
     'INVALID_UNICODE_ESCAPE',
     r"An escape sequence starting with '\u' must be followed by 4 hexadecimal digits or from 1 to 6 digits between '{' and '}'.");
 
+const ParserErrorCode _INVALID_USE_OF_COVARIANT_IN_EXTENSION =
+    const ParserErrorCode('INVALID_USE_OF_COVARIANT_IN_EXTENSION',
+        r"Can't have modifier '#lexeme' in an extension.",
+        correction: "Try removing '#lexeme'.");
+
 const ParserErrorCode _LIBRARY_DIRECTIVE_NOT_FIRST = const ParserErrorCode(
     'LIBRARY_DIRECTIVE_NOT_FIRST',
     r"The library directive must appear before all other directives.",
diff --git a/pkg/analyzer/lib/src/dart/resolver/ast_rewrite.dart b/pkg/analyzer/lib/src/dart/resolver/ast_rewrite.dart
index 756feb8..6a42394 100644
--- a/pkg/analyzer/lib/src/dart/resolver/ast_rewrite.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/ast_rewrite.dart
@@ -10,34 +10,21 @@
 import 'package:analyzer/src/dart/resolver/scope.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/type_system.dart';
 
-/// A visitor that will re-write an AST to support the optional `new` and
-/// `const` feature.
-class AstRewriteVisitor extends ScopedVisitor {
-  final TypeSystem typeSystem;
+/// Helper for [MethodInvocation]s into [InstanceCreationExpression] to support
+/// the optional `new` and `const` feature, or [ExtensionOverride].
+class AstRewriter {
+  final LibraryElement _libraryElement;
+  final ErrorReporter _errorReporter;
 
-  /// Initialize a newly created visitor.
-  AstRewriteVisitor(
-      this.typeSystem,
-      LibraryElement definingLibrary,
-      Source source,
-      TypeProvider typeProvider,
-      AnalysisErrorListener errorListener,
-      {Scope nameScope})
-      : super(definingLibrary, source, typeProvider, errorListener,
-            nameScope: nameScope);
+  AstRewriter(this._libraryElement, this._errorReporter);
 
-  @override
-  void visitMethodInvocation(MethodInvocation node) {
-    super.visitMethodInvocation(node);
-
+  AstNode methodInvocation(Scope nameScope, MethodInvocation node) {
     SimpleIdentifier methodName = node.methodName;
     if (methodName.isSynthetic) {
       // This isn't a constructor invocation because the method name is
       // synthetic.
-      return;
+      return node;
     }
 
     Expression target = node.target;
@@ -45,9 +32,9 @@
       // Possible cases: C() or C<>()
       if (node.realTarget != null) {
         // This isn't a constructor invocation because it's in a cascade.
-        return;
+        return node;
       }
-      Element element = nameScope.lookup(methodName, definingLibrary);
+      Element element = nameScope.lookup(methodName, _libraryElement);
       if (element is ClassElement) {
         TypeName typeName = astFactory.typeName(methodName, node.typeArguments);
         ConstructorName constructorName =
@@ -56,12 +43,14 @@
             astFactory.instanceCreationExpression(
                 null, constructorName, node.argumentList);
         NodeReplacer.replace(node, instanceCreationExpression);
+        return instanceCreationExpression;
       } else if (element is ExtensionElement) {
         ExtensionOverride extensionOverride = astFactory.extensionOverride(
             extensionName: methodName,
             typeArguments: node.typeArguments,
             argumentList: node.argumentList);
         NodeReplacer.replace(node, extensionOverride);
+        return extensionOverride;
       }
     } else if (target is SimpleIdentifier) {
       // Possible cases: C.n(), p.C() or p.C<>()
@@ -69,14 +58,14 @@
         // This isn't a constructor invocation because a null aware operator is
         // being used.
       }
-      Element element = nameScope.lookup(target, definingLibrary);
+      Element element = nameScope.lookup(target, _libraryElement);
       if (element is ClassElement) {
         // Possible case: C.n()
         var constructorElement = element.getNamedConstructor(methodName.name);
         if (constructorElement != null) {
           var typeArguments = node.typeArguments;
           if (typeArguments != null) {
-            errorReporter.reportErrorForNode(
+            _errorReporter.reportErrorForNode(
                 StaticTypeWarningCode
                     .WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR,
                 typeArguments,
@@ -91,6 +80,7 @@
                   null, constructorName, node.argumentList,
                   typeArguments: typeArguments);
           NodeReplacer.replace(node, instanceCreationExpression);
+          return instanceCreationExpression;
         }
       } else if (element is PrefixElement) {
         // Possible cases: p.C() or p.C<>()
@@ -98,7 +88,7 @@
             astFactory.simpleIdentifier(target.token),
             null,
             astFactory.simpleIdentifier(methodName.token));
-        Element prefixedElement = nameScope.lookup(identifier, definingLibrary);
+        Element prefixedElement = nameScope.lookup(identifier, _libraryElement);
         if (prefixedElement is ClassElement) {
           TypeName typeName = astFactory.typeName(
               astFactory.prefixedIdentifier(target, node.operator, methodName),
@@ -109,6 +99,7 @@
               astFactory.instanceCreationExpression(
                   null, constructorName, node.argumentList);
           NodeReplacer.replace(node, instanceCreationExpression);
+          return instanceCreationExpression;
         } else if (prefixedElement is ExtensionElement) {
           PrefixedIdentifier extensionName =
               astFactory.prefixedIdentifier(target, node.operator, methodName);
@@ -117,20 +108,21 @@
               typeArguments: node.typeArguments,
               argumentList: node.argumentList);
           NodeReplacer.replace(node, extensionOverride);
+          return extensionOverride;
         }
       }
     } else if (target is PrefixedIdentifier) {
       // Possible case: p.C.n()
-      Element prefixElement = nameScope.lookup(target.prefix, definingLibrary);
+      Element prefixElement = nameScope.lookup(target.prefix, _libraryElement);
       target.prefix.staticElement = prefixElement;
       if (prefixElement is PrefixElement) {
-        Element element = nameScope.lookup(target, definingLibrary);
+        Element element = nameScope.lookup(target, _libraryElement);
         if (element is ClassElement) {
           var constructorElement = element.getNamedConstructor(methodName.name);
           if (constructorElement != null) {
             var typeArguments = node.typeArguments;
             if (typeArguments != null) {
-              errorReporter.reportErrorForNode(
+              _errorReporter.reportErrorForNode(
                   StaticTypeWarningCode
                       .WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR,
                   typeArguments,
@@ -143,9 +135,11 @@
                 astFactory.instanceCreationExpression(
                     null, constructorName, node.argumentList);
             NodeReplacer.replace(node, instanceCreationExpression);
+            return instanceCreationExpression;
           }
         }
       }
     }
+    return node;
   }
 }
diff --git a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
index 48927a5..6cfd32a 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -10,33 +10,6 @@
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/variable_type_provider.dart';
 import 'package:front_end/src/fasta/flow_analysis/flow_analysis.dart';
-import 'package:meta/meta.dart';
-
-class AnalyzerFunctionBodyAccess
-    implements FunctionBodyAccess<PromotableElement> {
-  final FunctionBody node;
-
-  AnalyzerFunctionBodyAccess(this.node);
-
-  @override
-  bool isPotentiallyMutatedInClosure(PromotableElement variable) {
-    return node.isPotentiallyMutatedInClosure(variable);
-  }
-
-  @override
-  bool isPotentiallyMutatedInScope(PromotableElement variable) {
-    return node.isPotentiallyMutatedInScope(variable);
-  }
-}
-
-class AnalyzerNodeOperations implements NodeOperations<Expression> {
-  const AnalyzerNodeOperations();
-
-  @override
-  Expression unwrapParenthesized(Expression node) {
-    return node.unParenthesized;
-  }
-}
 
 /// The helper for performing flow analysis during resolution.
 ///
@@ -45,13 +18,10 @@
 /// be extracted.
 class FlowAnalysisHelper {
   /// The reused instance for creating new [FlowAnalysis] instances.
-  final NodeOperations<Expression> _nodeOperations;
-
-  /// The reused instance for creating new [FlowAnalysis] instances.
   final TypeSystemTypeOperations _typeOperations;
 
   /// Precomputed sets of potentially assigned variables.
-  final AssignedVariables<AstNode, PromotableElement> assignedVariables;
+  AssignedVariables<AstNode, PromotableElement> assignedVariables;
 
   /// The result for post-resolution stages of analysis.
   final FlowAnalysisResult result;
@@ -59,19 +29,12 @@
   /// The current flow, when resolving a function body, or `null` otherwise.
   FlowAnalysis<Statement, Expression, PromotableElement, DartType> flow;
 
-  int _blockFunctionBodyLevel = 0;
-
-  factory FlowAnalysisHelper(
-      TypeSystem typeSystem, AstNode node, bool retainDataForTesting) {
-    return FlowAnalysisHelper._(
-        const AnalyzerNodeOperations(),
-        TypeSystemTypeOperations(typeSystem),
-        computeAssignedVariables(node),
+  factory FlowAnalysisHelper(TypeSystem typeSystem, bool retainDataForTesting) {
+    return FlowAnalysisHelper._(TypeSystemTypeOperations(typeSystem),
         retainDataForTesting ? FlowAnalysisResult() : null);
   }
 
-  FlowAnalysisHelper._(this._nodeOperations, this._typeOperations,
-      this.assignedVariables, this.result);
+  FlowAnalysisHelper._(this._typeOperations, this.result);
 
   LocalVariableTypeProvider get localVariableTypeProvider {
     return _LocalVariableTypeProvider(this);
@@ -99,28 +62,6 @@
     flow.write(localElement);
   }
 
-  void binaryExpression_equal(
-      BinaryExpression node, Expression left, Expression right,
-      {@required bool notEqual}) {
-    if (flow == null) return;
-
-    if (right is NullLiteral) {
-      if (left is SimpleIdentifier) {
-        var element = left.staticElement;
-        if (element is VariableElement) {
-          flow.conditionEqNull(node, element, notEqual: notEqual);
-        }
-      }
-    } else if (left is NullLiteral) {
-      if (right is SimpleIdentifier) {
-        var element = right.staticElement;
-        if (element is VariableElement) {
-          flow.conditionEqNull(node, element, notEqual: notEqual);
-        }
-      }
-    }
-  }
-
   void breakStatement(BreakStatement node) {
     var target = getLabelTarget(node, node.label?.staticElement);
     flow.handleBreak(target);
@@ -148,54 +89,35 @@
     flow.handleContinue(target);
   }
 
+  void executableDeclaration_enter(
+      Declaration node, FormalParameterList parameters, bool isClosure) {
+    if (parameters != null) {
+      for (var parameter in parameters.parameters) {
+        flow.initialize(parameter.declaredElement);
+      }
+    }
+
+    if (isClosure) {
+      flow.functionExpression_begin(assignedVariables.writtenInNode(node));
+    }
+  }
+
+  void executableDeclaration_exit(FunctionBody body, bool isClosure) {
+    if (isClosure) {
+      flow.functionExpression_end();
+    }
+    if (!flow.isReachable) {
+      result?.functionBodiesThatDontComplete?.add(body);
+    }
+  }
+
   void for_bodyBegin(AstNode node, Expression condition) {
     flow.for_bodyBegin(node is Statement ? node : null, condition);
   }
 
   void for_conditionBegin(AstNode node, Expression condition) {
-    var assigned = assignedVariables.writtenInNode(node);
-    flow.for_conditionBegin(assigned);
-  }
-
-  void functionBody_enter(FunctionBody node) {
-    _blockFunctionBodyLevel++;
-
-    if (_blockFunctionBodyLevel > 1) {
-      assert(flow != null);
-    } else {
-      flow = FlowAnalysis<Statement, Expression, PromotableElement, DartType>(
-        _nodeOperations,
-        _typeOperations,
-        AnalyzerFunctionBodyAccess(node),
-      );
-    }
-
-    var parameters = _enclosingExecutableParameters(node);
-    if (parameters != null) {
-      for (var parameter in parameters.parameters) {
-        flow.write(parameter.declaredElement);
-      }
-    }
-  }
-
-  void functionBody_exit(FunctionBody node) {
-    _blockFunctionBodyLevel--;
-
-    if (_blockFunctionBodyLevel > 0) {
-      return;
-    }
-
-    // Set this.flow to null before doing any clean-up so that if an exception
-    // is raised, the state is already updated correctly, and we don't have
-    // cascading failures.
-    var flow = this.flow;
-    this.flow = null;
-
-    if (!flow.isReachable) {
-      result?.functionBodiesThatDontComplete?.add(node);
-    }
-
-    flow.finish();
+    flow.for_conditionBegin(assignedVariables.writtenInNode(node),
+        assignedVariables.capturedInNode(node));
   }
 
   void isExpression(IsExpression node) {
@@ -244,37 +166,48 @@
     return false;
   }
 
+  void topLevelDeclaration_enter(
+      Declaration node, FormalParameterList parameters, FunctionBody body) {
+    assert(node != null);
+    assert(flow == null);
+    assignedVariables = computeAssignedVariables(node, parameters);
+    flow = FlowAnalysis<Statement, Expression, PromotableElement, DartType>(
+        _typeOperations,
+        assignedVariables.writtenAnywhere,
+        assignedVariables.capturedAnywhere);
+  }
+
+  void topLevelDeclaration_exit() {
+    // Set this.flow to null before doing any clean-up so that if an exception
+    // is raised, the state is already updated correctly, and we don't have
+    // cascading failures.
+    var flow = this.flow;
+    this.flow = null;
+    assignedVariables = null;
+
+    flow.finish();
+  }
+
   void variableDeclarationList(VariableDeclarationList node) {
     if (flow != null) {
       var variables = node.variables;
       for (var i = 0; i < variables.length; ++i) {
         var variable = variables[i];
         if (variable.initializer != null) {
-          flow.write(variable.declaredElement);
+          flow.initialize(variable.declaredElement);
         }
       }
     }
   }
 
-  FormalParameterList _enclosingExecutableParameters(FunctionBody node) {
-    var parent = node.parent;
-    if (parent is ConstructorDeclaration) {
-      return parent.parameters;
-    }
-    if (parent is FunctionExpression) {
-      return parent.parameters;
-    }
-    if (parent is MethodDeclaration) {
-      return parent.parameters;
-    }
-    return null;
-  }
-
   /// Computes the [AssignedVariables] map for the given [node].
   static AssignedVariables<AstNode, PromotableElement> computeAssignedVariables(
-      AstNode node) {
+      Declaration node, FormalParameterList parameters) {
     var assignedVariables = AssignedVariables<AstNode, PromotableElement>();
-    node.accept(_AssignedVariablesVisitor(assignedVariables));
+    var assignedVariablesVisitor = _AssignedVariablesVisitor(assignedVariables);
+    assignedVariablesVisitor._declareParameters(parameters);
+    node.visitChildren(assignedVariablesVisitor);
+    assignedVariables.finish();
     return assignedVariables;
   }
 
@@ -377,10 +310,22 @@
   }
 
   @override
+  void visitCatchClause(CatchClause node) {
+    for (var identifier in [
+      node.exceptionParameter,
+      node.stackTraceParameter
+    ]) {
+      if (identifier != null) {
+        assignedVariables
+            .declare(identifier.staticElement as PromotableElement);
+      }
+    }
+    super.visitCatchClause(node);
+  }
+
+  @override
   void visitConstructorDeclaration(ConstructorDeclaration node) {
-    assignedVariables.beginNode();
-    super.visitConstructorDeclaration(node);
-    assignedVariables.endNode(node);
+    throw StateError('Should not visit top level declarations');
   }
 
   @override
@@ -402,26 +347,28 @@
 
   @override
   void visitFunctionDeclaration(FunctionDeclaration node) {
-    bool isClosure = node.parent is! CompilationUnit;
-    assignedVariables.beginNode(isClosure: isClosure);
+    if (node.parent is CompilationUnit) {
+      throw StateError('Should not visit top level declarations');
+    }
+    assignedVariables.beginNode();
+    _declareParameters(node.functionExpression.parameters);
     // Note: we bypass this.visitFunctionExpression so that the function
     // expression isn't mistaken for a closure.
     super.visitFunctionExpression(node.functionExpression);
-    assignedVariables.endNode(node, isClosure: isClosure);
+    assignedVariables.endNode(node, isClosure: true);
   }
 
   @override
   void visitFunctionExpression(FunctionExpression node) {
-    assignedVariables.beginNode(isClosure: true);
+    assignedVariables.beginNode();
+    _declareParameters(node.parameters);
     super.visitFunctionExpression(node);
     assignedVariables.endNode(node, isClosure: true);
   }
 
   @override
   void visitMethodDeclaration(MethodDeclaration node) {
-    assignedVariables.beginNode();
-    super.visitMethodDeclaration(node);
-    assignedVariables.endNode(node);
+    throw StateError('Should not visit top level declarations');
   }
 
   @override
@@ -453,12 +400,30 @@
   }
 
   @override
+  void visitVariableDeclaration(VariableDeclaration node) {
+    var grandParent = node.parent.parent;
+    if (grandParent is TopLevelVariableDeclaration ||
+        grandParent is FieldDeclaration) {
+      throw StateError('Should not visit top level declarations');
+    }
+    assignedVariables.declare(node.declaredElement);
+    super.visitVariableDeclaration(node);
+  }
+
+  @override
   void visitWhileStatement(WhileStatement node) {
     assignedVariables.beginNode();
     super.visitWhileStatement(node);
     assignedVariables.endNode(node);
   }
 
+  void _declareParameters(FormalParameterList parameters) {
+    if (parameters == null) return;
+    for (var parameter in parameters.parameters) {
+      assignedVariables.declare(parameter.declaredElement);
+    }
+  }
+
   void _handleFor(AstNode node, ForLoopParts forLoopParts, AstNode body) {
     if (forLoopParts is ForParts) {
       if (forLoopParts is ForPartsWithExpression) {
@@ -486,7 +451,9 @@
           assignedVariables.write(element);
         }
       } else if (forLoopParts is ForEachPartsWithDeclaration) {
-        assignedVariables.write(forLoopParts.loopVariable.declaredElement);
+        var variable = forLoopParts.loopVariable.declaredElement;
+        assignedVariables.declare(variable);
+        assignedVariables.write(variable);
       } else {
         throw new StateError('Unrecognized for loop parts');
       }
@@ -507,7 +474,10 @@
   @override
   DartType getType(SimpleIdentifier node) {
     var variable = node.staticElement as VariableElement;
-    var promotedType = _manager.flow?.promotedType(variable);
-    return promotedType ?? variable.type;
+    if (variable is PromotableElement) {
+      var promotedType = _manager.flow?.variableRead(node, variable);
+      if (promotedType != null) return promotedType;
+    }
+    return variable.type;
   }
 }
diff --git a/pkg/analyzer/lib/src/dart/resolver/inheritance_manager.dart b/pkg/analyzer/lib/src/dart/resolver/inheritance_manager.dart
index 16e1ba9..68b1179 100644
--- a/pkg/analyzer/lib/src/dart/resolver/inheritance_manager.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/inheritance_manager.dart
@@ -439,8 +439,6 @@
     }
     executable.returnType = dynamicType;
     executable.parameters = parameters;
-    FunctionTypeImpl methodType = new FunctionTypeImpl(executable);
-    executable.type = methodType;
     return executable;
   }
 
diff --git a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
new file mode 100644
index 0000000..c71d6f2
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
@@ -0,0 +1,1266 @@
+// 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/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/dart/element/type.dart';
+import 'package:analyzer/error/error.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+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/error/codes.dart';
+import 'package:analyzer/src/generated/declaration_resolver.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/utilities_dart.dart';
+import 'package:meta/meta.dart';
+
+class ElementHolder {
+  final ElementImpl _element;
+  final List<TypeParameterElementImpl> _typeParameters = [];
+  final List<ParameterElementImpl> _parameters = [];
+
+  ElementHolder(this._element) : assert(_element != null);
+
+  List<ParameterElementImpl> get parameters => _parameters;
+
+  List<TypeParameterElementImpl> get typeParameters => _typeParameters;
+
+  void addParameter(ParameterElementImpl element) {
+    _parameters.add(element);
+  }
+
+  void addTypeParameter(TypeParameterElementImpl element) {
+    _typeParameters.add(element);
+  }
+
+  void enclose(ElementImpl element) {
+    element.enclosingElement = _element;
+  }
+}
+
+/// Recursively visit AST and perform following resolution tasks:
+///
+/// 1. Set existing top-level elements from [_elementWalker] to corresponding
+///    nodes in AST.
+/// 2. Create and set new elements for local declarations.
+/// 3. Resolve all [TypeName]s - set elements and types.
+/// 4. Resolve all [GenericFunctionType]s - set their types.
+class ResolutionVisitor extends RecursiveAstVisitor<void> {
+  final TypeProvider _typeProvider;
+  final CompilationUnitElementImpl _unitElement;
+  final bool _nonNullableEnabled;
+  final ErrorReporter _errorReporter;
+  final AstRewriter _astRewriter;
+  final TypeNameResolver _typeNameResolver;
+
+  /// 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
+  /// and formal parameters to apply to corresponding AST nodes.
+  ElementWalker _elementWalker;
+
+  /// The scope used to resolve identifiers.
+  Scope _nameScope;
+
+  /// The scope used to resolve labels for `break` and `continue` statements,
+  /// or `null` if no labels have been defined in the current context.
+  LabelScope _labelScope;
+
+  /// The container to add newly created elements that should be put into the
+  /// enclosing element.
+  ElementHolder _elementHolder;
+
+  /// The flag specifying if currently visited class references 'super'
+  /// expression.
+  /// TODO(scheglov) put into summary
+  bool _hasReferenceToSuper = false;
+
+  factory ResolutionVisitor({
+    @required CompilationUnitElementImpl unitElement,
+    @required AnalysisErrorListener errorListener,
+    @required FeatureSet featureSet,
+    @required Scope nameScope,
+    ElementWalker elementWalker,
+  }) {
+    var libraryElement = unitElement.library;
+    var typeProvider = libraryElement.context.typeProvider;
+    var unitSource = unitElement.source;
+    var nonNullableEnabled = featureSet.isEnabled(Feature.non_nullable);
+    var errorReporter = ErrorReporter(errorListener, unitSource);
+
+    var typeNameResolver = TypeNameResolver(
+      unitElement.context.typeSystem,
+      typeProvider,
+      nonNullableEnabled,
+      libraryElement,
+      unitSource,
+      errorListener,
+    );
+
+    return ResolutionVisitor._(
+      typeProvider,
+      unitElement,
+      nonNullableEnabled,
+      errorReporter,
+      AstRewriter(libraryElement, errorReporter),
+      typeNameResolver,
+      nameScope,
+      elementWalker,
+      ElementHolder(unitElement),
+    );
+  }
+
+  ResolutionVisitor._(
+    this._typeProvider,
+    this._unitElement,
+    this._nonNullableEnabled,
+    this._errorReporter,
+    this._astRewriter,
+    this._typeNameResolver,
+    this._nameScope,
+    this._elementWalker,
+    this._elementHolder,
+  );
+
+  DartType get _dynamicType => _typeProvider.dynamicType;
+
+  @override
+  void visitAnnotation(Annotation node) {
+    _withElementWalker(null, () {
+      super.visitAnnotation(node);
+    });
+  }
+
+  @override
+  void visitBlock(Block node) {
+    var outerScope = _nameScope;
+    try {
+      _nameScope = EnclosedScope(_nameScope);
+
+      var statements = node.statements;
+      _buildLocalElements(statements);
+      statements.accept(this);
+    } finally {
+      _nameScope = outerScope;
+    }
+  }
+
+  @override
+  void visitCatchClause(CatchClause node) {
+    var exceptionTypeNode = node.exceptionType;
+    exceptionTypeNode?.accept(this);
+
+    _withNameScope(() {
+      var exceptionNode = node.exceptionParameter;
+      if (exceptionNode != null) {
+        var element = LocalVariableElementImpl.forNode(exceptionNode);
+        _elementHolder.enclose(element);
+        _nameScope.define(element);
+
+        exceptionNode.staticElement = element;
+
+        if (exceptionTypeNode == null) {
+          element.hasImplicitType = true;
+          element.declaredType = _dynamicType;
+          exceptionNode.staticType = _dynamicType;
+        } else {
+          element.declaredType = exceptionTypeNode.type;
+          exceptionNode.staticType = exceptionTypeNode.type;
+        }
+
+        _setCodeRange(element, exceptionNode);
+        element.setVisibleRange(node.offset, node.length);
+      }
+
+      var stackTraceNode = node.stackTraceParameter;
+      if (stackTraceNode != null) {
+        var element = LocalVariableElementImpl.forNode(stackTraceNode);
+        _elementHolder.enclose(element);
+        _nameScope.define(element);
+
+        stackTraceNode.staticElement = element;
+
+        element.declaredType = _typeProvider.stackTraceType;
+        stackTraceNode.staticType = _typeProvider.stackTraceType;
+
+        _setCodeRange(element, stackTraceNode);
+        element.setVisibleRange(node.offset, node.length);
+      }
+
+      node.body.accept(this);
+    });
+  }
+
+  @override
+  void visitClassDeclaration(ClassDeclaration node) {
+    ClassElementImpl element = _elementWalker.getClass();
+    node.name.staticElement = element;
+
+    node.metadata.accept(this);
+    _setElementAnnotations(node.metadata, element.metadata);
+
+    _withElementWalker(ElementWalker.forClass(element), () {
+      _withNameScope(() {
+        _buildTypeParameterElements(node.typeParameters);
+        node.typeParameters?.accept(this);
+
+        var extendsClause = node.extendsClause;
+        var withClause = node.withClause;
+
+        if (extendsClause != null) {
+          ErrorCode errorCode = withClause == null
+              ? CompileTimeErrorCode.EXTENDS_NON_CLASS
+              : CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS;
+          _resolveType(extendsClause.superclass, errorCode, asClass: true);
+        }
+
+        _resolveWithClause(withClause);
+        _resolveImplementsClause(node.implementsClause);
+
+        _hasReferenceToSuper = false;
+
+        _defineElements(element.accessors);
+        _defineElements(element.methods);
+        node.members.accept(this);
+
+        element.hasReferenceToSuper = _hasReferenceToSuper;
+      });
+    });
+  }
+
+  @override
+  void visitClassTypeAlias(ClassTypeAlias node) {
+    ClassElementImpl element = _elementWalker.getClass();
+    node.name.staticElement = element;
+
+    node.metadata.accept(this);
+    _setElementAnnotations(node.metadata, element.metadata);
+
+    _withElementWalker(ElementWalker.forClass(element), () {
+      _withNameScope(() {
+        _buildTypeParameterElements(node.typeParameters);
+        node.typeParameters?.accept(this);
+
+        _resolveType(
+          node.superclass,
+          CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS,
+          asClass: true,
+        );
+
+        _resolveWithClause(node.withClause);
+        _resolveImplementsClause(node.implementsClause);
+      });
+    });
+  }
+
+  @override
+  void visitConstructorDeclaration(ConstructorDeclaration node) {
+    ConstructorElementImpl element = _elementWalker.getConstructor();
+    (node as ConstructorDeclarationImpl).declaredElement = element;
+    node.name?.staticElement = element;
+
+    node.metadata.accept(this);
+    _setElementAnnotations(node.metadata, element.metadata);
+
+    _withElementHolder(ElementHolder(element), () {
+      _withElementWalker(null, () {
+        _withNameScope(() {
+          node.returnType.accept(this);
+
+          _withElementWalker(
+            ElementWalker.forExecutable(element, _unitElement),
+            () {
+              node.parameters.accept(this);
+            },
+          );
+          _defineParameters(element.parameters);
+
+          node.redirectedConstructor?.accept(this);
+          node.initializers.accept(this);
+          node.body?.accept(this);
+        });
+      });
+    });
+  }
+
+  @override
+  void visitDeclaredIdentifier(DeclaredIdentifier node) {
+    var nameNode = node.identifier;
+    var element = LocalVariableElementImpl.forNode(nameNode);
+    _elementHolder.enclose(element);
+    nameNode.staticElement = element;
+
+    node.metadata.accept(this);
+    element.metadata = _createElementAnnotations(node.metadata);
+
+    element.isConst = node.isConst;
+    element.isFinal = node.isFinal;
+
+    if (node.type == null) {
+      element.hasImplicitType = true;
+      element.type = _dynamicType;
+    } else {
+      node.type.accept(this);
+      element.type = node.type.type;
+    }
+
+    _setCodeRange(element, node);
+
+    var parent = node.parent;
+    if (parent is ForEachPartsWithDeclaration) {
+      var statement = parent.parent;
+      element.setVisibleRange(statement.offset, statement.length);
+    }
+  }
+
+  @override
+  void visitDefaultFormalParameter(DefaultFormalParameter node) {
+    NormalFormalParameter normalParameter = node.parameter;
+    SimpleIdentifier nameNode = normalParameter.identifier;
+
+    ParameterElementImpl element;
+    if (_elementWalker != null) {
+      element = _elementWalker.getParameter();
+    } else {
+      element = DefaultParameterElementImpl.forNode(nameNode);
+      _elementHolder.addParameter(element);
+
+      _setCodeRange(element, node);
+      element.isConst = node.isConst;
+      element.isExplicitlyCovariant = node.parameter.covariantKeyword != null;
+      element.isFinal = node.isFinal;
+      // ignore: deprecated_member_use_from_same_package
+      element.parameterKind = node.kind;
+      _setParameterVisibleRange(node, element);
+
+      if (normalParameter is SimpleFormalParameter &&
+          normalParameter.type == null) {
+        element.hasImplicitType = true;
+      }
+    }
+
+    if (normalParameter is SimpleFormalParameterImpl) {
+      normalParameter.declaredElement = element;
+    }
+    nameNode?.staticElement = element;
+
+    normalParameter.accept(this);
+
+    var defaultValue = node.defaultValue;
+    if (defaultValue != null) {
+      _withElementWalker(null, () {
+        var offset = defaultValue.offset;
+        var initializer = FunctionElementImpl.forOffset(offset);
+        element.initializer = initializer;
+
+        initializer.hasImplicitReturnType = true;
+        initializer.isSynthetic = true;
+
+        _withElementHolder(ElementHolder(initializer), () {
+          defaultValue.accept(this);
+        });
+      });
+      element.defaultValueCode = defaultValue.toSource();
+    }
+  }
+
+  @override
+  void visitEnumConstantDeclaration(EnumConstantDeclaration node) {
+    var element = _elementWalker.getVariable();
+    node.name.staticElement = element;
+
+    node.metadata.accept(this);
+    _setElementAnnotations(node.metadata, element.metadata);
+  }
+
+  @override
+  void visitEnumDeclaration(EnumDeclaration node) {
+    EnumElementImpl element = _elementWalker.getEnum();
+    node.name.staticElement = element;
+
+    node.metadata.accept(this);
+    _setElementAnnotations(node.metadata, element.metadata);
+
+    _withElementWalker(ElementWalker.forClass(element), () {
+      _withNameScope(() {
+        _defineElements(element.accessors);
+        node.constants.accept(this);
+      });
+    });
+  }
+
+  @override
+  void visitExportDirective(ExportDirective node) {
+    super.visitExportDirective(node);
+    if (node.element != null) {
+      _setElementAnnotations(node.metadata, node.element.metadata);
+    }
+  }
+
+  @override
+  void visitExtensionDeclaration(ExtensionDeclaration node) {
+    var element = _elementWalker.getExtension();
+    (node as ExtensionDeclarationImpl).declaredElement = element;
+    node.name?.staticElement = element;
+
+    node.metadata.accept(this);
+    _setElementAnnotations(node.metadata, element.metadata);
+
+    _withElementWalker(ElementWalker.forExtension(element), () {
+      _withNameScope(() {
+        _buildTypeParameterElements(node.typeParameters);
+        node.typeParameters?.accept(this);
+        node.extendedType.accept(this);
+
+        _defineElements(element.accessors);
+        _defineElements(element.methods);
+        node.members.accept(this);
+      });
+    });
+  }
+
+  @override
+  void visitFieldDeclaration(FieldDeclaration node) {
+    super.visitFieldDeclaration(node);
+    FieldElement firstFieldElement = node.fields.variables[0].declaredElement;
+    _setElementAnnotations(node.metadata, firstFieldElement.metadata);
+  }
+
+  @override
+  void visitFieldFormalParameter(FieldFormalParameter node) {
+    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);
+    }
+    node.identifier.staticElement = element;
+
+    node.metadata.accept(this);
+    _setElementAnnotations(node.metadata, element.metadata);
+
+    _withElementHolder(ElementHolder(element), () {
+      _withNameScope(() {
+        _buildTypeParameterElements(node.typeParameters);
+        node.typeParameters?.accept(this);
+        node.type?.accept(this);
+        if (_elementWalker != null) {
+          _withElementWalker(ElementWalker.forParameter(element), () {
+            node.parameters?.accept(this);
+          });
+        } else {
+          // Only for recovery, this should not happen in valid code.
+          element.type = node.type?.type ?? _dynamicType;
+          _withElementWalker(null, () {
+            node.parameters?.accept(this);
+          });
+        }
+      });
+    });
+  }
+
+  @override
+  void visitFunctionDeclaration(FunctionDeclaration node) {
+    ExecutableElementImpl element;
+    if (_elementWalker != null) {
+      element = node.isGetter || node.isSetter
+          ? _elementWalker.getAccessor()
+          : _elementWalker.getFunction();
+      node.name.staticElement = element;
+    } else {
+      // Elements for local variables and functions are built before we
+      // start visiting a Block.
+      element = node.declaredElement;
+
+      _setCodeRange(element, node);
+      setElementDocumentationComment(element, node);
+      element.metadata = _createElementAnnotations(node.metadata);
+
+      FunctionBody body = node.functionExpression.body;
+      if (node.externalKeyword != null || body is NativeFunctionBody) {
+        element.external = true;
+      }
+
+      element.asynchronous = body.isAsynchronous;
+      element.generator = body.isGenerator;
+      if (node.returnType == null) {
+        element.hasImplicitReturnType = true;
+      }
+
+      var enclosingBlock = node.thisOrAncestorOfType<Block>();
+      if (enclosingBlock != null) {
+        (element as FunctionElementImpl)
+            .setVisibleRange(enclosingBlock.offset, enclosingBlock.length);
+      }
+    }
+
+    FunctionExpressionImpl expression = node.functionExpression;
+    expression.declaredElement = element;
+
+    node.metadata?.accept(this);
+    _setElementAnnotations(node.metadata, element.metadata);
+
+    var holder = ElementHolder(element);
+    _withElementHolder(holder, () {
+      _withElementWalker(
+        _elementWalker != null
+            ? ElementWalker.forExecutable(element, _unitElement)
+            : null,
+        () {
+          _withNameScope(() {
+            _buildTypeParameterElements(expression.typeParameters);
+            expression.typeParameters?.accept(this);
+            if (_elementWalker == null) {
+              element.typeParameters = holder.typeParameters;
+            }
+
+            expression.parameters?.accept(this);
+            if (_elementWalker == null) {
+              element.parameters = holder.parameters;
+            }
+
+            node.returnType?.accept(this);
+            if (_elementWalker == null) {
+              element.returnType = node.returnType?.type ?? _dynamicType;
+            }
+
+            _defineParameters(element.parameters);
+            _withElementWalker(null, () {
+              expression.body.accept(this);
+            });
+          });
+        },
+      );
+    });
+  }
+
+  @override
+  void visitFunctionExpression(FunctionExpression node) {
+    var element = FunctionElementImpl.forOffset(node.offset);
+    _elementHolder.enclose(element);
+    (node as FunctionExpressionImpl).declaredElement = element;
+
+    element.hasImplicitReturnType = true;
+
+    FunctionBody body = node.body;
+    element.asynchronous = body.isAsynchronous;
+    element.generator = body.isGenerator;
+
+    var holder = ElementHolder(element);
+    _withElementHolder(holder, () {
+      _withNameScope(() {
+        _buildTypeParameterElements(node.typeParameters);
+        node.typeParameters?.accept(this);
+        element.typeParameters = holder.typeParameters;
+
+        node.parameters.accept(this);
+        element.parameters = holder.parameters;
+
+        _defineParameters(element.parameters);
+        node.body.accept(this);
+      });
+    });
+
+    _setCodeRange(element, node);
+
+    var enclosingBlock = node.thisOrAncestorOfType<Block>();
+    if (enclosingBlock != null) {
+      element.setVisibleRange(enclosingBlock.offset, enclosingBlock.length);
+    }
+  }
+
+  @override
+  void visitFunctionTypeAlias(FunctionTypeAlias node) {
+    var element = _elementWalker.getTypedef();
+    node.name.staticElement = element;
+
+    node.metadata?.accept(this);
+    _setElementAnnotations(node.metadata, element.metadata);
+
+    _withElementWalker(ElementWalker.forTypedef(element), () {
+      _withNameScope(() {
+        _buildTypeParameterElements(node.typeParameters);
+        node.typeParameters?.accept(this);
+        node.returnType?.accept(this);
+        node.parameters?.accept(this);
+      });
+    });
+  }
+
+  @override
+  void visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
+    ParameterElementImpl element;
+    if (node.parent is DefaultFormalParameter) {
+      element = node.declaredElement;
+    } else {
+      SimpleIdentifier nameNode = node.identifier;
+      if (_elementWalker != null) {
+        element = _elementWalker.getParameter();
+      } else {
+        element = new ParameterElementImpl.forNode(nameNode);
+        _elementHolder.addParameter(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);
+        _setParameterVisibleRange(node, element);
+      }
+      nameNode.staticElement = element;
+    }
+
+    node.metadata?.accept(this);
+    element.metadata = _createElementAnnotations(node.metadata);
+
+    var holder = ElementHolder(element);
+    _withElementHolder(holder, () {
+      _withElementWalker(
+        _elementWalker != null ? ElementWalker.forParameter(element) : null,
+        () {
+          _withNameScope(() {
+            _buildTypeParameterElements(node.typeParameters);
+            node.typeParameters?.accept(this);
+            if (_elementWalker == null) {
+              element.typeParameters = holder.typeParameters;
+            }
+
+            node.parameters.accept(this);
+            if (_elementWalker == null) {
+              element.parameters = holder.parameters;
+            }
+
+            node.returnType?.accept(this);
+            if (_elementWalker == null) {
+              element.type = FunctionTypeImpl.synthetic(
+                node.returnType?.type ?? _dynamicType,
+                element.typeParameters,
+                element.parameters,
+                nullabilitySuffix: _getNullability(node.question != null),
+              );
+            }
+          });
+        },
+      );
+    });
+  }
+
+  @override
+  void visitGenericFunctionType(GenericFunctionType node) {
+    var element = GenericFunctionTypeElementImpl.forOffset(node.offset);
+    _unitElement.encloseElement(element);
+    (node as GenericFunctionTypeImpl).declaredElement = element;
+
+    _setCodeRange(element, node);
+
+    var holder = ElementHolder(element);
+    _withElementHolder(holder, () {
+      _withElementWalker(null, () {
+        _withNameScope(() {
+          _buildTypeParameterElements(node.typeParameters);
+          node.typeParameters?.accept(this);
+          element.typeParameters = holder.typeParameters;
+
+          node.parameters.accept(this);
+          element.parameters = holder.parameters;
+
+          node.returnType?.accept(this);
+          element.returnType = node.returnType?.type ?? _dynamicType;
+        });
+      });
+    });
+
+    var type = FunctionTypeImpl.synthetic(
+      element.returnType,
+      element.typeParameters,
+      element.parameters,
+      nullabilitySuffix: _getNullability(node.question != null),
+    );
+    element.type = type;
+    (node as GenericFunctionTypeImpl).type = type;
+  }
+
+  @override
+  void visitGenericTypeAlias(GenericTypeAlias node) {
+    var element = _elementWalker.getTypedef();
+    node.name.staticElement = element;
+
+    node.metadata.accept(this);
+    _setElementAnnotations(node.metadata, element.metadata);
+
+    _withElementWalker(ElementWalker.forGenericTypeAlias(element), () {
+      _withNameScope(() {
+        _buildTypeParameterElements(node.typeParameters);
+        node.typeParameters?.accept(this);
+        node.functionType?.accept(this);
+      });
+    });
+  }
+
+  @override
+  void visitImportDirective(ImportDirective node) {
+    super.visitImportDirective(node);
+    if (node.element != null) {
+      _setElementAnnotations(node.metadata, node.element.metadata);
+    }
+  }
+
+  @override
+  void visitLabeledStatement(LabeledStatement node) {
+    bool onSwitchStatement = node.statement is SwitchStatement;
+    _buildLabelElements(node.labels, onSwitchStatement, false);
+
+    var outerScope = _labelScope;
+    try {
+      var unlabeled = node.unlabeled;
+      for (Label label in node.labels) {
+        SimpleIdentifier labelNameNode = label.label;
+        _labelScope = LabelScope(
+          _labelScope,
+          labelNameNode.name,
+          unlabeled,
+          labelNameNode.staticElement as LabelElement,
+        );
+      }
+      unlabeled.accept(this);
+    } finally {
+      _labelScope = outerScope;
+    }
+  }
+
+  @override
+  void visitLibraryDirective(LibraryDirective node) {
+    super.visitLibraryDirective(node);
+    if (node.element != null) {
+      _setElementAnnotations(node.metadata, node.element.metadata);
+    }
+  }
+
+  @override
+  void visitMethodDeclaration(MethodDeclaration node) {
+    ExecutableElementImpl element = node.isGetter || node.isSetter
+        ? _elementWalker.getAccessor()
+        : _elementWalker.getFunction();
+    node.name.staticElement = element;
+
+    node.metadata.accept(this);
+    _setElementAnnotations(node.metadata, element.metadata);
+
+    _withElementWalker(ElementWalker.forExecutable(element, _unitElement), () {
+      node.metadata.accept(this);
+      _withNameScope(() {
+        _buildTypeParameterElements(node.typeParameters);
+        node.typeParameters?.accept(this);
+        node.parameters?.accept(this);
+        node.returnType?.accept(this);
+
+        _withElementWalker(null, () {
+          _withElementHolder(ElementHolder(element), () {
+            _defineParameters(element.parameters);
+            node.body?.accept(this);
+          });
+        });
+      });
+    });
+  }
+
+  @override
+  void visitMethodInvocation(MethodInvocation node) {
+    var newNode = _astRewriter.methodInvocation(_nameScope, node);
+    if (newNode != node) {
+      return newNode.accept(this);
+    }
+
+    super.visitMethodInvocation(node);
+  }
+
+  @override
+  void visitMixinDeclaration(MixinDeclaration node) {
+    var element = _elementWalker.getMixin();
+    node.name.staticElement = element;
+
+    node.metadata.accept(this);
+    _setElementAnnotations(node.metadata, element.metadata);
+
+    _withElementWalker(ElementWalker.forClass(element), () {
+      _withNameScope(() {
+        _buildTypeParameterElements(node.typeParameters);
+        node.typeParameters?.accept(this);
+
+        _resolveOnClause(node.onClause);
+        _resolveImplementsClause(node.implementsClause);
+
+        _defineElements(element.accessors);
+        _defineElements(element.methods);
+        node.members.accept(this);
+      });
+    });
+  }
+
+  @override
+  void visitPartDirective(PartDirective node) {
+    super.visitPartDirective(node);
+    if (node.element != null) {
+      _setElementAnnotations(node.metadata, node.element.metadata);
+    }
+  }
+
+  @override
+  void visitSimpleFormalParameter(SimpleFormalParameter node) {
+    ParameterElementImpl element;
+    if (node.parent is DefaultFormalParameter) {
+      element = node.declaredElement;
+    } else {
+      SimpleIdentifier nameNode = node.identifier;
+      if (_elementWalker != null) {
+        element = _elementWalker.getParameter();
+      } else {
+        element = ParameterElementImpl.forNode(nameNode);
+        _elementHolder.addParameter(element);
+
+        _setCodeRange(element, node);
+        element.isConst = node.isConst;
+        element.isExplicitlyCovariant = node.covariantKeyword != null;
+        element.isFinal = node.isFinal;
+        // ignore: deprecated_member_use_from_same_package
+        element.parameterKind = node.kind;
+        _setParameterVisibleRange(node, element);
+        if (node.type == null) {
+          element.hasImplicitType = true;
+        }
+        (node as SimpleFormalParameterImpl).declaredElement = element;
+      }
+      nameNode?.staticElement = element;
+      (node as SimpleFormalParameterImpl).declaredElement = element;
+    }
+
+    node.type?.accept(this);
+    if (_elementWalker == null) {
+      element.metadata = _createElementAnnotations(node.metadata);
+      element.type = node.type?.type ?? _dynamicType;
+    }
+
+    node.metadata.accept(this);
+    _setElementAnnotations(node.metadata, element.metadata);
+  }
+
+  @override
+  void visitSuperExpression(SuperExpression node) {
+    _hasReferenceToSuper = true;
+    super.visitSuperExpression(node);
+  }
+
+  @override
+  void visitSwitchCase(SwitchCase node) {
+    _buildLabelElements(node.labels, false, true);
+
+    node.expression.accept(this);
+
+    _withNameScope(() {
+      var statements = node.statements;
+      _buildLocalElements(statements);
+      statements.accept(this);
+    });
+  }
+
+  @override
+  void visitSwitchDefault(SwitchDefault node) {
+    _buildLabelElements(node.labels, false, true);
+
+    _withNameScope(() {
+      var statements = node.statements;
+      _buildLocalElements(statements);
+      statements.accept(this);
+    });
+  }
+
+  @override
+  void visitTypeName(TypeName node) {
+    node.typeArguments?.accept(this);
+
+    _typeNameResolver.nameScope = _nameScope;
+    _typeNameResolver.resolveTypeName(node);
+
+    if (_typeNameResolver.rewriteResult != null) {
+      _typeNameResolver.rewriteResult.accept(this);
+    }
+  }
+
+  @override
+  void visitTypeParameter(TypeParameter node) {
+    TypeParameterElementImpl element = node.declaredElement;
+
+    node.metadata?.accept(this);
+    _setElementAnnotations(node.metadata, element.metadata);
+
+    var boundNode = node.bound;
+    if (boundNode != null) {
+      boundNode.accept(this);
+      if (_elementWalker == null) {
+        element.bound = boundNode.type;
+
+        element.metadata = _createElementAnnotations(node.metadata);
+        _setCodeRange(element, node);
+      }
+    }
+  }
+
+  @override
+  void visitVariableDeclaration(VariableDeclaration node) {
+    Expression initializerNode = node.initializer;
+
+    VariableElementImpl element;
+    if (_elementWalker != null) {
+      element = _elementWalker.getVariable();
+      node.name.staticElement = element;
+    } else {
+      bool isConst = node.isConst;
+      bool isFinal = node.isFinal;
+      SimpleIdentifier variableName = node.name;
+
+      LocalVariableElementImpl localElement;
+      if (isConst && initializerNode != null) {
+        localElement = ConstLocalVariableElementImpl.forNode(variableName);
+      } else {
+        localElement = LocalVariableElementImpl.forNode(variableName);
+      }
+      _elementHolder.enclose(localElement);
+      variableName.staticElement = localElement;
+      element = localElement;
+
+      localElement.isConst = isConst;
+      localElement.isFinal = isFinal;
+      localElement.isLate = node.isLate;
+
+      VariableDeclarationList varList = node.parent;
+      localElement.hasImplicitType = varList.type == null;
+      localElement.type = varList.type?.type ?? _dynamicType;
+
+      _setVariableVisibleRange(localElement, node);
+    }
+
+    if (initializerNode != null) {
+      _withElementWalker(null, () {
+        var offset = initializerNode.offset;
+        var initializer = FunctionElementImpl.forOffset(offset);
+        element.initializer = initializer;
+
+        initializer.hasImplicitReturnType = true;
+        initializer.isSynthetic = true;
+
+        _withElementHolder(ElementHolder(initializer), () {
+          initializerNode.accept(this);
+        });
+      });
+    }
+  }
+
+  @override
+  void visitVariableDeclarationList(VariableDeclarationList node) {
+    super.visitVariableDeclarationList(node);
+
+    List<ElementAnnotation> elementAnnotations;
+    AstNode parent = node.parent;
+    if (parent is FieldDeclaration) {
+      elementAnnotations = _createElementAnnotations(parent.metadata);
+    } else if (parent is TopLevelVariableDeclaration) {
+      elementAnnotations = _createElementAnnotations(parent.metadata);
+    } else {
+      // Local variable declaration
+      elementAnnotations = _createElementAnnotations(node.metadata);
+    }
+
+    var variables = node.variables;
+    for (var i = 0; i < variables.length; i++) {
+      var variable = variables[i];
+      var element = variable.declaredElement as ElementImpl;
+      element.metadata = elementAnnotations;
+
+      var offset = (i == 0 ? node.parent : variable).offset;
+      var length = variable.end - offset;
+      element.setCodeRange(offset, length);
+    }
+  }
+
+  /// Builds the label elements associated with [labels] and stores them in the
+  /// element holder.
+  void _buildLabelElements(
+      List<Label> labels, bool onSwitchStatement, bool onSwitchMember) {
+    for (Label label in labels) {
+      var labelName = label.label;
+      var element = LabelElementImpl.forNode(
+          labelName, onSwitchStatement, onSwitchMember);
+      labelName.staticElement = element;
+      _elementHolder.enclose(element);
+    }
+  }
+
+  void _buildLocalElements(List<Statement> statements) {
+    for (var statement in statements) {
+      if (statement is FunctionDeclarationStatement) {
+        var declaration = statement.functionDeclaration;
+        var element = FunctionElementImpl.forNode(declaration.name);
+        declaration.name.staticElement = element;
+        _nameScope.define(element);
+        _elementHolder.enclose(element);
+      } else if (statement is VariableDeclarationStatement) {
+        for (var variable in statement.variables.variables) {
+          var element = LocalVariableElementImpl(
+            variable.name.name,
+            variable.name.offset,
+          );
+          variable.name.staticElement = element;
+          _nameScope.define(element);
+          _elementHolder.enclose(element);
+        }
+      }
+    }
+  }
+
+  /// Ensure that each type parameters from the [typeParameterList] has its
+  /// element set, either from the [_elementWalker] or new, and define these
+  /// elements in the [_nameScope].
+  void _buildTypeParameterElements(TypeParameterList typeParameterList) {
+    if (typeParameterList == null) return;
+
+    for (var typeParameter in typeParameterList.typeParameters) {
+      var name = typeParameter.name;
+
+      TypeParameterElementImpl element;
+      if (_elementWalker != null) {
+        element = _elementWalker.getTypeParameter();
+      } else {
+        element = TypeParameterElementImpl.forNode(name);
+        _elementHolder.addTypeParameter(element);
+      }
+      name.staticElement = element;
+      _nameScope.define(element);
+    }
+  }
+
+  /**
+   * For each [Annotation] found in [annotations], create a new
+   * [ElementAnnotation] object and set the [Annotation] to point to it.
+   */
+  List<ElementAnnotation> _createElementAnnotations(
+      List<Annotation> annotations) {
+    if (annotations.isEmpty) {
+      return const <ElementAnnotation>[];
+    }
+    return annotations.map((Annotation a) {
+      var elementAnnotation = ElementAnnotationImpl(_unitElement);
+      a.elementAnnotation = elementAnnotation;
+      return elementAnnotation;
+    }).toList();
+  }
+
+  /// Define given [elements] in the [_nameScope].
+  void _defineElements(List<Element> elements) {
+    int length = elements.length;
+    for (int i = 0; i < length; i++) {
+      var element = elements[i];
+      _nameScope.define(element);
+    }
+  }
+
+  /// Define given [parameters] in the [_nameScope].
+  void _defineParameters(List<ParameterElement> parameters) {
+    int length = parameters.length;
+    for (int i = 0; i < length; i++) {
+      ParameterElement parameter = parameters[i];
+      if (!parameter.isInitializingFormal) {
+        _nameScope.define(parameter);
+      }
+    }
+  }
+
+  /// Return the body of the function that contains the given [parameter], or
+  /// `null` if no function body could be found.
+  FunctionBody _getFunctionBody(FormalParameter parameter) {
+    AstNode parent = parameter?.parent?.parent;
+    if (parent is ConstructorDeclaration) {
+      return parent.body;
+    } else if (parent is FunctionExpression) {
+      return parent.body;
+    } else if (parent is MethodDeclaration) {
+      return parent.body;
+    }
+    return null;
+  }
+
+  NullabilitySuffix _getNullability(bool hasQuestion) {
+    NullabilitySuffix nullability;
+    if (_nonNullableEnabled) {
+      if (hasQuestion) {
+        nullability = NullabilitySuffix.question;
+      } else {
+        nullability = NullabilitySuffix.none;
+      }
+    } else {
+      nullability = NullabilitySuffix.star;
+    }
+    return nullability;
+  }
+
+  void _resolveImplementsClause(ImplementsClause clause) {
+    if (clause == null) return;
+
+    _resolveTypes(
+      clause.interfaces,
+      CompileTimeErrorCode.IMPLEMENTS_NON_CLASS,
+    );
+  }
+
+  void _resolveOnClause(OnClause clause) {
+    if (clause == null) return;
+
+    _resolveTypes(
+      clause.superclassConstraints,
+      CompileTimeErrorCode.MIXIN_SUPER_CLASS_CONSTRAINT_NON_INTERFACE,
+    );
+  }
+
+  /// Return the [InterfaceType] of the given [typeName].
+  ///
+  /// If the resulting type is not a valid interface type, return `null`.
+  ///
+  /// The flag [asClass] specifies if the type will be used as a class, so mixin
+  /// declarations are not valid (they declare interfaces and mixins, but not
+  /// classes).
+  void _resolveType(TypeName typeName, ErrorCode errorCode,
+      {bool asClass: false}) {
+    visitTypeName(typeName);
+
+    DartType type = typeName.type;
+    if (type is InterfaceType) {
+      ClassElement element = type.element;
+      if (element.isEnum || element.isMixin && asClass) {
+        _errorReporter.reportErrorForNode(errorCode, typeName);
+        return;
+      }
+      return;
+    }
+
+    // If the type is not an InterfaceType, then visitTypeName() sets the type
+    // to be a DynamicTypeImpl
+    Identifier name = typeName.name;
+    if (!_nameScope.shouldIgnoreUndefined(name)) {
+      _errorReporter.reportErrorForNode(errorCode, name, [name.name]);
+    }
+  }
+
+  /// Resolve the types in the given list of type names.
+  ///
+  /// @param typeNames the type names to be resolved
+  /// @param nonTypeError the error to produce if the type name is defined to be
+  ///        something other than a type
+  /// @param enumTypeError the error to produce if the type name is defined to
+  ///        be an enum
+  /// @param dynamicTypeError the error to produce if the type name is "dynamic"
+  /// @return an array containing all of the types that were resolved.
+  void _resolveTypes(NodeList<TypeName> typeNames, ErrorCode errorCode) {
+    for (TypeName typeName in typeNames) {
+      _resolveType(typeName, errorCode);
+    }
+  }
+
+  void _resolveWithClause(WithClause clause) {
+    if (clause == null) return;
+
+    _resolveTypes(
+      clause.mixinTypes,
+      CompileTimeErrorCode.MIXIN_OF_NON_CLASS,
+    );
+  }
+
+  void _setCodeRange(ElementImpl element, AstNode node) {
+    element.setCodeRange(node.offset, node.length);
+  }
+
+  /// Sets the visible source range for formal parameter.
+  void _setParameterVisibleRange(
+      FormalParameter node, ParameterElementImpl element) {
+    FunctionBody body = _getFunctionBody(node);
+    if (body is BlockFunctionBody || body is ExpressionFunctionBody) {
+      element.setVisibleRange(body.offset, body.length);
+    }
+  }
+
+  void _setVariableVisibleRange(
+      LocalVariableElementImpl element, VariableDeclaration node) {
+    AstNode scopeNode;
+    AstNode parent2 = node.parent.parent;
+    if (parent2 is ForPartsWithDeclarations) {
+      scopeNode = parent2.parent;
+    } else {
+      scopeNode = node.thisOrAncestorOfType<Block>();
+    }
+    element.setVisibleRange(scopeNode.offset, scopeNode.length);
+  }
+
+  /// Make the given [holder] be the current one while running [f].
+  void _withElementHolder(ElementHolder holder, void Function() f) {
+    var previousHolder = _elementHolder;
+    _elementHolder = holder;
+    try {
+      f();
+    } finally {
+      _elementHolder = previousHolder;
+    }
+  }
+
+  /// Make the given [walker] be the current one while running [f].
+  void _withElementWalker(ElementWalker walker, void Function() f) {
+    var current = _elementWalker;
+    try {
+      _elementWalker = walker;
+      f();
+    } finally {
+      _elementWalker = current;
+    }
+  }
+
+  /// Run [f] with the new name scope.
+  void _withNameScope(void Function() f) {
+    var current = _nameScope;
+    try {
+      _nameScope = EnclosedScope(current);
+      f();
+    } finally {
+      _nameScope = current;
+    }
+  }
+
+  /// Associate each of the annotation [nodes] with the corresponding
+  /// [ElementAnnotation] in [annotations].
+  static void _setElementAnnotations(
+      List<Annotation> nodes, List<ElementAnnotation> annotations) {
+    int nodeCount = nodes.length;
+    if (nodeCount != annotations.length) {
+      throw StateError(
+        'Found $nodeCount annotation nodes and '
+        '${annotations.length} element annotations',
+      );
+    }
+    for (int i = 0; i < nodeCount; i++) {
+      nodes[i].elementAnnotation = annotations[i];
+    }
+  }
+}
diff --git a/pkg/analyzer/lib/src/dart/sdk/sdk.dart b/pkg/analyzer/lib/src/dart/sdk/sdk.dart
index b3432d7..4f9c23e 100644
--- a/pkg/analyzer/lib/src/dart/sdk/sdk.dart
+++ b/pkg/analyzer/lib/src/dart/sdk/sdk.dart
@@ -896,7 +896,7 @@
     Parser parser = new Parser(source, errorListener, featureSet: featureSet);
     CompilationUnit unit = parser.parseCompilationUnit(scanner.tokenize());
     SdkLibrariesReader_LibraryBuilder libraryBuilder =
-        new SdkLibrariesReader_LibraryBuilder(true);
+        new SdkLibrariesReader_LibraryBuilder();
     // If any syntactic errors were found then don't try to visit the AST
     // structure.
     if (!errorListener.errorReported) {
diff --git a/pkg/analyzer/lib/src/error/codes.dart b/pkg/analyzer/lib/src/error/codes.dart
index 9c49a15..5d68cd4 100644
--- a/pkg/analyzer/lib/src/error/codes.dart
+++ b/pkg/analyzer/lib/src/error/codes.dart
@@ -2599,40 +2599,9 @@
               "methods or before non-final instance fields.",
           correction: "Try removing the 'covariant' keyword.");
 
-  /**
-   * No parameters.
-   */
-  // #### Description
-  //
-  // The analyzer produces this diagnostic when a member declared inside an
-  // extension uses the keyword `covariant` in the declaration of a parameter.
-  // Extensions aren't classes and don't have subclasses, so the keyword serves
-  // no purpose.
-  //
-  // #### Example
-  //
-  // The following code produces this diagnostic:
-  //
-  // ```dart
-  // extension E on String {
-  //   void a([!covariant!] int i) {}
-  // }
-  // ```
-  //
-  // #### Common fixes
-  //
-  // Remove the 'covariant' keyword:
-  //
-  // ```dart
-  // extension E on String {
-  //   void a(int i) {}
-  // }
-  // ```
-  static const CompileTimeErrorCode INVALID_USE_OF_COVARIANT_IN_EXTENSION =
-      const CompileTimeErrorCode('INVALID_USE_OF_COVARIANT_IN_EXTENSION',
-          "The 'covariant' keyword can't be used in an extension.",
-          correction: "Try removing the 'covariant' keyword.",
-          hasPublishedDocs: true);
+  @Deprecated('Use ParserErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION')
+  static const ParserErrorCode INVALID_USE_OF_COVARIANT_IN_EXTENSION =
+      ParserErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION;
 
   /**
    * 14.2 Exports: It is a compile-time error if the compilation unit found at
diff --git a/pkg/analyzer/lib/src/error/inheritance_override.dart b/pkg/analyzer/lib/src/error/inheritance_override.dart
index ac9b421..6640df9 100644
--- a/pkg/analyzer/lib/src/error/inheritance_override.dart
+++ b/pkg/analyzer/lib/src/error/inheritance_override.dart
@@ -123,8 +123,7 @@
     this.superclass,
     this.withClause,
   })  : libraryUri = library.source.uri,
-        classElement =
-            AbstractClassElementImpl.getImpl(classNameNode.staticElement);
+        classElement = classNameNode.staticElement;
 
   void verify() {
     if (_checkDirectSuperTypes()) {
diff --git a/pkg/analyzer/lib/src/error/required_parameters_verifier.dart b/pkg/analyzer/lib/src/error/required_parameters_verifier.dart
index 6bd0134..f82c80a 100644
--- a/pkg/analyzer/lib/src/error/required_parameters_verifier.dart
+++ b/pkg/analyzer/lib/src/error/required_parameters_verifier.dart
@@ -19,17 +19,20 @@
 
   @override
   void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
-    _checkForMissingRequiredParam(
-      node.staticInvokeType,
-      node.argumentList,
-      node,
-    );
+    var type = node.staticInvokeType;
+    if (type is FunctionType) {
+      _check(
+        type.parameters,
+        node.argumentList,
+        node,
+      );
+    }
   }
 
   @override
   void visitInstanceCreationExpression(InstanceCreationExpression node) {
-    _checkForMissingRequiredParam(
-      node.staticElement?.type,
+    _check(
+      node.staticElement?.parameters,
       node.argumentList,
       node.constructorName,
     );
@@ -37,8 +40,8 @@
 
   @override
   void visitMethodInvocation(MethodInvocation node) {
-    _checkForMissingRequiredParam(
-      node.staticInvokeType,
+    _check(
+      _executableElement(node.methodName.staticElement)?.parameters,
       node.argumentList,
       node.methodName,
     );
@@ -47,8 +50,8 @@
   @override
   void visitRedirectingConstructorInvocation(
       RedirectingConstructorInvocation node) {
-    _checkForMissingRequiredParam(
-      node.staticElement?.type,
+    _check(
+      _executableElement(node.staticElement)?.parameters,
       node.argumentList,
       node,
     );
@@ -56,49 +59,51 @@
 
   @override
   void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
-    _checkForMissingRequiredParam(
-      node.staticElement?.type,
+    _check(
+      _executableElement(node.staticElement)?.parameters,
       node.argumentList,
       node,
     );
   }
 
-  void _checkForMissingRequiredParam(
-    DartType type,
+  void _check(
+    List<ParameterElement> parameters,
     ArgumentList argumentList,
     AstNode node,
   ) {
-    if (type is FunctionType) {
-      for (ParameterElement parameter in type.parameters) {
-        if (parameter.isRequiredNamed) {
+    if (parameters == null) {
+      return;
+    }
+
+    for (ParameterElement parameter in parameters) {
+      if (parameter.isRequiredNamed) {
+        String parameterName = parameter.name;
+        if (!_containsNamedExpression(argumentList, parameterName)) {
+          _errorReporter.reportErrorForNode(
+            CompileTimeErrorCode.MISSING_REQUIRED_ARGUMENT,
+            node,
+            [parameterName],
+          );
+        }
+      }
+      if (parameter.isOptionalNamed) {
+        ElementAnnotationImpl annotation = _requiredAnnotation(parameter);
+        if (annotation != null) {
           String parameterName = parameter.name;
           if (!_containsNamedExpression(argumentList, parameterName)) {
-            _errorReporter.reportErrorForNode(
-              CompileTimeErrorCode.MISSING_REQUIRED_ARGUMENT,
-              node,
-              [parameterName],
-            );
-          }
-        }
-        if (parameter.isOptionalNamed) {
-          ElementAnnotationImpl annotation = _requiredAnnotation(parameter);
-          if (annotation != null) {
-            String parameterName = parameter.name;
-            if (!_containsNamedExpression(argumentList, parameterName)) {
-              String reason = _requiredReason(annotation);
-              if (reason != null) {
-                _errorReporter.reportErrorForNode(
-                  HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS,
-                  node,
-                  [parameterName, reason],
-                );
-              } else {
-                _errorReporter.reportErrorForNode(
-                  HintCode.MISSING_REQUIRED_PARAM,
-                  node,
-                  [parameterName],
-                );
-              }
+            String reason = _requiredReason(annotation);
+            if (reason != null) {
+              _errorReporter.reportErrorForNode(
+                HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS,
+                node,
+                [parameterName, reason],
+              );
+            } else {
+              _errorReporter.reportErrorForNode(
+                HintCode.MISSING_REQUIRED_PARAM,
+                node,
+                [parameterName],
+              );
             }
           }
         }
@@ -119,6 +124,14 @@
     return false;
   }
 
+  static ExecutableElement _executableElement(Element element) {
+    if (element is ExecutableElement) {
+      return element;
+    } else {
+      return null;
+    }
+  }
+
   static ElementAnnotationImpl _requiredAnnotation(ParameterElement element) {
     return element.metadata.firstWhere(
       (e) => e.isRequired,
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 9b42e29..20ab282 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -2107,6 +2107,16 @@
     assert(extendsOrSuper == null ||
         optional('extends', extendsOrSuper) ||
         optional('super', extendsOrSuper));
+
+    // TODO (kallentu): Implement variance behaviour for the analyzer.
+    assert(variance == null ||
+        optional('in', variance) ||
+        optional('out', variance) ||
+        optional('inout', variance));
+    if (!enableVariance) {
+      reportVarianceModifierNotEnabled(variance);
+    }
+
     TypeAnnotation bound = pop();
 
     // Peek to leave type parameters on top of stack.
@@ -3355,14 +3365,6 @@
   }
 
   @override
-  void handleVarianceModifier(Token variance) {
-    debugEvent('VarianceModifier');
-    if (!enableVariance) {
-      reportVarianceModifierNotEnabled(variance);
-    }
-  }
-
-  @override
   void handleVoidKeyword(Token voidKeyword) {
     assert(optional('void', voidKeyword));
     debugEvent("VoidKeyword");
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 17b73d5..16190aa 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -874,8 +874,7 @@
 
   @override
   void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
-    ClassElementImpl enclosingClass =
-        AbstractClassElementImpl.getImpl(_resolver.enclosingClass);
+    ClassElementImpl enclosingClass = _resolver.enclosingClass;
     if (enclosingClass == null) {
       // TODO(brianwilkerson) Report this error.
       return;
@@ -1660,9 +1659,7 @@
             if (element != null) {
               propertyName.staticElement = element;
               ClassElementImpl receiverSuperClass =
-                  AbstractClassElementImpl.getImpl(
-                staticType.element.supertype.element,
-              );
+                  staticType.element.supertype.element;
               if (!receiverSuperClass.hasNoSuchMethod) {
                 _resolver.errorReporter.reportErrorForNode(
                   CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE,
@@ -1697,9 +1694,7 @@
             if (element != null) {
               propertyName.staticElement = element;
               ClassElementImpl receiverSuperClass =
-                  AbstractClassElementImpl.getImpl(
-                staticType.element.supertype.element,
-              );
+                  staticType.element.supertype.element;
               if (!receiverSuperClass.hasNoSuchMethod) {
                 _resolver.errorReporter.reportErrorForNode(
                   CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE,
@@ -1771,6 +1766,8 @@
         var setter = result.setter;
         if (setter != null) {
           propertyName.staticElement = setter;
+          propertyName.auxiliaryElements =
+              AuxiliaryElements(result.getter, null);
         } else {
           var getter = result.getter;
           propertyName.staticElement = getter;
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index ec27a69..8fe0222 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -2,7 +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:collection';
 import 'dart:typed_data';
 
 import 'package:analyzer/dart/analysis/features.dart';
@@ -96,12 +95,6 @@
 
   /// Return a type system for this context.
   TypeSystem get typeSystem;
-
-  /// Apply the changes specified by the given [changeSet] to this context. Any
-  /// analysis results that have been invalidated by these changes will be
-  /// removed.
-  /// TODO(scheglov) This method is referenced by the internal indexer tool.
-  void applyChanges(ChangeSet changeSet);
 }
 
 /// The entry point for the functionality provided by the analysis engine. There
@@ -875,193 +868,6 @@
   static bool _analyzeNoFunctionBodies(Source _) => false;
 }
 
-/// An indication of which sources have been added, changed, removed, or deleted.
-/// In the case of a changed source, there are multiple ways of indicating the
-/// nature of the change.
-///
-/// No source should be added to the change set more than once, either with the
-/// same or a different kind of change. It does not make sense, for example, for
-/// a source to be both added and removed, and it is redundant for a source to be
-/// marked as changed in its entirety and changed in some specific range.
-class ChangeSet {
-  /// A list containing the sources that have been added.
-  final List<Source> addedSources = new List<Source>();
-
-  /// A list containing the sources that have been changed.
-  final List<Source> changedSources = new List<Source>();
-
-  /// A table mapping the sources whose content has been changed to the current
-  /// content of those sources.
-  Map<Source, String> _changedContent = new HashMap<Source, String>();
-
-  /// A table mapping the sources whose content has been changed within a single
-  /// range to the current content of those sources and information about the
-  /// affected range.
-  final HashMap<Source, ChangeSet_ContentChange> changedRanges =
-      new HashMap<Source, ChangeSet_ContentChange>();
-
-  /// A list containing the sources that have been removed.
-  final List<Source> removedSources = new List<Source>();
-
-  /// A list containing the source containers specifying additional sources that
-  /// have been removed.
-  final List<SourceContainer> removedContainers = new List<SourceContainer>();
-
-  /// Return a table mapping the sources whose content has been changed to the
-  /// current content of those sources.
-  Map<Source, String> get changedContents => _changedContent;
-
-  /// Return `true` if this change set does not contain any changes.
-  bool get isEmpty =>
-      addedSources.isEmpty &&
-      changedSources.isEmpty &&
-      _changedContent.isEmpty &&
-      changedRanges.isEmpty &&
-      removedSources.isEmpty &&
-      removedContainers.isEmpty;
-
-  /// Record that the specified [source] has been added and that its content is
-  /// the default contents of the source.
-  void addedSource(Source source) {
-    addedSources.add(source);
-  }
-
-  /// Record that the specified [source] has been changed and that its content is
-  /// the given [contents].
-  void changedContent(Source source, String contents) {
-    _changedContent[source] = contents;
-  }
-
-  /// Record that the specified [source] has been changed and that its content is
-  /// the given [contents]. The [offset] is the offset into the current contents.
-  /// The [oldLength] is the number of characters in the original contents that
-  /// were replaced. The [newLength] is the number of characters in the
-  /// replacement text.
-  void changedRange(Source source, String contents, int offset, int oldLength,
-      int newLength) {
-    changedRanges[source] =
-        new ChangeSet_ContentChange(contents, offset, oldLength, newLength);
-  }
-
-  /// Record that the specified [source] has been changed. If the content of the
-  /// source was previously overridden, this has no effect (the content remains
-  /// overridden). To cancel (or change) the override, use [changedContent]
-  /// instead.
-  void changedSource(Source source) {
-    changedSources.add(source);
-  }
-
-  /// Record that the specified source [container] has been removed.
-  void removedContainer(SourceContainer container) {
-    if (container != null) {
-      removedContainers.add(container);
-    }
-  }
-
-  /// Record that the specified [source] has been removed.
-  void removedSource(Source source) {
-    if (source != null) {
-      removedSources.add(source);
-    }
-  }
-
-  @override
-  String toString() {
-    StringBuffer buffer = new StringBuffer();
-    bool needsSeparator =
-        _appendSources(buffer, addedSources, false, "addedSources");
-    needsSeparator = _appendSources(
-        buffer, changedSources, needsSeparator, "changedSources");
-    needsSeparator = _appendSources2(
-        buffer, _changedContent, needsSeparator, "changedContent");
-    needsSeparator =
-        _appendSources2(buffer, changedRanges, needsSeparator, "changedRanges");
-    needsSeparator = _appendSources(
-        buffer, removedSources, needsSeparator, "removedSources");
-    int count = removedContainers.length;
-    if (count > 0) {
-      if (removedSources.isEmpty) {
-        if (needsSeparator) {
-          buffer.write("; ");
-        }
-        buffer.write("removed: from ");
-        buffer.write(count);
-        buffer.write(" containers");
-      } else {
-        buffer.write(", and more from ");
-        buffer.write(count);
-        buffer.write(" containers");
-      }
-    }
-    return buffer.toString();
-  }
-
-  /// Append the given [sources] to the given [buffer], prefixed with the given
-  /// [label] and a separator if [needsSeparator] is `true`. Return `true` if
-  /// future lists of sources will need a separator.
-  bool _appendSources(StringBuffer buffer, List<Source> sources,
-      bool needsSeparator, String label) {
-    if (sources.isEmpty) {
-      return needsSeparator;
-    }
-    if (needsSeparator) {
-      buffer.write("; ");
-    }
-    buffer.write(label);
-    String prefix = " ";
-    for (Source source in sources) {
-      buffer.write(prefix);
-      buffer.write(source.fullName);
-      prefix = ", ";
-    }
-    return true;
-  }
-
-  /// Append the given [sources] to the given [builder], prefixed with the given
-  /// [label] and a separator if [needsSeparator] is `true`. Return `true` if
-  /// future lists of sources will need a separator.
-  bool _appendSources2(StringBuffer buffer, Map<Source, dynamic> sources,
-      bool needsSeparator, String label) {
-    if (sources.isEmpty) {
-      return needsSeparator;
-    }
-    if (needsSeparator) {
-      buffer.write("; ");
-    }
-    buffer.write(label);
-    String prefix = " ";
-    for (Source source in sources.keys.toSet()) {
-      buffer.write(prefix);
-      buffer.write(source.fullName);
-      prefix = ", ";
-    }
-    return true;
-  }
-}
-
-/// A change to the content of a source.
-class ChangeSet_ContentChange {
-  /// The new contents of the source.
-  final String contents;
-
-  /// The offset into the current contents.
-  final int offset;
-
-  /// The number of characters in the original contents that were replaced
-  final int oldLength;
-
-  /// The number of characters in the replacement text.
-  final int newLength;
-
-  /// Initialize a newly created change object to represent a change to the
-  /// content of a source. The [contents] is the new contents of the source. The
-  /// [offset] is the offset into the current contents. The [oldLength] is the
-  /// number of characters in the original contents that were replaced. The
-  /// [newLength] is the number of characters in the replacement text.
-  ChangeSet_ContentChange(
-      this.contents, this.offset, this.oldLength, this.newLength);
-}
-
 /// Additional behavior for an analysis context that is required by internal
 /// users of the context.
 abstract class InternalAnalysisContext implements AnalysisContext {
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index c279188..4bef170 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -531,7 +531,7 @@
     ClassElementImpl outerClass = _enclosingClass;
     try {
       _isInNativeClass = node.nativeClause != null;
-      _enclosingClass = AbstractClassElementImpl.getImpl(node.declaredElement);
+      _enclosingClass = node.declaredElement;
 
       List<ClassMember> members = node.members;
       _duplicateDefinitionVerifier.checkClass(node);
@@ -569,7 +569,7 @@
         node.name, CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME);
     ClassElementImpl outerClassElement = _enclosingClass;
     try {
-      _enclosingClass = AbstractClassElementImpl.getImpl(node.declaredElement);
+      _enclosingClass = node.declaredElement;
       _checkClassInheritance(
           node, node.superclass, node.withClause, node.implementsClause);
       _checkForWrongTypeParameterVarianceInSuperinterfaces();
@@ -1111,7 +1111,7 @@
     // TODO(scheglov) Verify for all mixin errors.
     ClassElementImpl outerClass = _enclosingClass;
     try {
-      _enclosingClass = AbstractClassElementImpl.getImpl(node.declaredElement);
+      _enclosingClass = node.declaredElement;
 
       List<ClassMember> members = node.members;
       _duplicateDefinitionVerifier.checkMixin(node);
@@ -2709,7 +2709,13 @@
     }
 
     // The type of the loop variable.
-    DartType variableType = getStaticType(variable);
+    DartType variableType;
+    var variableElement = variable.staticElement;
+    if (variableElement is VariableElement) {
+      variableType = variableElement.type;
+    } else {
+      return false;
+    }
 
     AstNode parent = node.parent;
     Token awaitKeyword;
@@ -3904,8 +3910,7 @@
   /// implementations of all the super-invoked members of the [mixinElement].
   bool _checkForMixinSuperInvokedMembers(int mixinIndex, TypeName mixinName,
       ClassElement mixinElement, InterfaceType mixinType) {
-    ClassElementImpl mixinElementImpl =
-        AbstractClassElementImpl.getImpl(mixinElement);
+    ClassElementImpl mixinElementImpl = mixinElement;
     if (mixinElementImpl.superInvokedNames.isEmpty) {
       return false;
     }
@@ -5497,10 +5502,7 @@
       Token keyword = parameter.covariantKeyword;
       if (keyword != null) {
         if (_enclosingExtension != null) {
-          _errorReporter.reportErrorForToken(
-            CompileTimeErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION,
-            keyword,
-          );
+          // Reported by the parser.
         } else {
           _errorReporter.reportErrorForToken(
             CompileTimeErrorCode.INVALID_USE_OF_COVARIANT,
diff --git a/pkg/analyzer/lib/src/generated/ffi_verifier.dart b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
new file mode 100644
index 0000000..9e6b40d
--- /dev/null
+++ b/pkg/analyzer/lib/src/generated/ffi_verifier.dart
@@ -0,0 +1,577 @@
+// 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/ast/ast.dart';
+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/error/listener.dart';
+import 'package:analyzer/src/dart/error/ffi_code.dart';
+
+/// A visitor used to find problems with the way the `dart:ffi` APIs are being
+/// used. See 'pkg/vm/lib/transformations/ffi_checks.md' for the specification
+/// of the desired hints.
+class FfiVerifier extends RecursiveAstVisitor<void> {
+  /// The type system used to check types.
+  final TypeSystem typeSystem;
+
+  /// The error reporter used to report errors.
+  final ErrorReporter _errorReporter;
+
+  /// A flag indicating whether we are currently visiting inside a subclass of
+  /// `Struct`.
+  bool inStruct = false;
+
+  /// Initialize a newly created verifier.
+  FfiVerifier(this.typeSystem, this._errorReporter);
+
+  @override
+  void visitClassDeclaration(ClassDeclaration node) {
+    inStruct = false;
+    // Only the Struct class may be extended.
+    ExtendsClause extendsClause = node.extendsClause;
+    if (extendsClause != null) {
+      final TypeName superclass = extendsClause.superclass;
+      if (_isDartFfiClass(superclass)) {
+        if (superclass.name.staticElement.name == 'Struct') {
+          inStruct = true;
+        } else {
+          _errorReporter.reportTypeErrorForNode(
+              FfiCode.SUBTYPE_OF_FFI_CLASS_IN_EXTENDS,
+              superclass.name,
+              [node.name.name, superclass.name.name]);
+        }
+      } else if (_isSubtypeOfStruct(superclass)) {
+        _errorReporter.reportTypeErrorForNode(
+            FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_EXTENDS,
+            superclass,
+            [node.name.name, superclass.name.name]);
+      }
+    }
+
+    // No classes from the FFI may be explicitly implemented.
+    void checkSupertype(TypeName typename, FfiCode subtypeOfFfiCode,
+        FfiCode subtypeOfStructCode) {
+      if (_isDartFfiClass(typename)) {
+        _errorReporter.reportTypeErrorForNode(
+            subtypeOfFfiCode, typename, [node.name, typename.name]);
+      } else if (_isSubtypeOfStruct(typename)) {
+        _errorReporter.reportTypeErrorForNode(
+            subtypeOfStructCode, typename, [node.name, typename.name]);
+      }
+    }
+
+    ImplementsClause implementsClause = node.implementsClause;
+    if (implementsClause != null) {
+      for (TypeName type in implementsClause.interfaces) {
+        checkSupertype(type, FfiCode.SUBTYPE_OF_FFI_CLASS_IN_IMPLEMENTS,
+            FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_IMPLEMENTS);
+      }
+    }
+    WithClause withClause = node.withClause;
+    if (withClause != null) {
+      for (TypeName type in withClause.mixinTypes) {
+        checkSupertype(type, FfiCode.SUBTYPE_OF_FFI_CLASS_IN_WITH,
+            FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_WITH);
+      }
+    }
+
+    if (inStruct && node.declaredElement.typeParameters.isNotEmpty) {
+      _errorReporter.reportErrorForNode(
+          FfiCode.GENERIC_STRUCT_SUBCLASS, node.name, [node.name]);
+    }
+    super.visitClassDeclaration(node);
+  }
+
+  @override
+  void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
+    if (inStruct) {
+      _errorReporter.reportErrorForNode(
+          FfiCode.FIELD_INITIALIZER_IN_STRUCT, node);
+    }
+    super.visitConstructorFieldInitializer(node);
+  }
+
+  @override
+  void visitFieldDeclaration(FieldDeclaration node) {
+    if (inStruct) {
+      _validateFieldsInStruct(node);
+    }
+    super.visitFieldDeclaration(node);
+  }
+
+  @override
+  void visitMethodInvocation(MethodInvocation node) {
+    Element element = node.methodName.staticElement;
+    if (element is MethodElement) {
+      Element enclosingElement = element.enclosingElement;
+      if (enclosingElement is ClassElement) {
+        if (_isPointer(enclosingElement)) {
+          if (element.name == 'asFunction') {
+            _validateAsFunction(node, element);
+          } else if (element.name == 'fromFunction') {
+            _validateFromFunction(node, element);
+          }
+        } else if (_isDynamicLibrary(enclosingElement) &&
+            element.name == 'lookupFunction') {
+          _validateLookupFunction(node);
+        }
+      }
+    }
+    super.visitMethodInvocation(node);
+  }
+
+  /// Return `true` if the [typeName] is the name of a type from `dart:ffi`.
+  bool _isDartFfiClass(TypeName typeName) =>
+      _isDartFfiElement(typeName.name.staticElement);
+
+  /// Return `true` if the [element] is a class element from `dart:ffi`.
+  bool _isDartFfiElement(Element element) {
+    if (element is ConstructorElement) {
+      element = element.enclosingElement;
+    }
+    return element is ClassElement && element.library.name == 'dart.ffi';
+  }
+
+  /// Return `true` if the given [element] represents the class
+  /// `DynamicLibrary`.
+  bool _isDynamicLibrary(ClassElement element) =>
+      element.name == 'DynamicLibrary' && element.library.name == 'dart.ffi';
+
+  /// Return `true` if the given [element] represents the class `Pointer`.
+  bool _isPointer(ClassElement element) =>
+      element.name == 'Pointer' && element.library.name == 'dart.ffi';
+
+  /// Return `true` if the [typeName] represents a subtype of `Struct`.
+  bool _isSubtypeOfStruct(TypeName typeName) {
+    Element superType = typeName.name.staticElement;
+    if (superType is ClassElement) {
+      bool isStruct(InterfaceType type) {
+        return type != null &&
+            type.element.name == 'Struct' &&
+            type.element.library.name == 'dart.ffi';
+      }
+
+      return isStruct(superType.supertype) ||
+          superType.interfaces.any(isStruct) ||
+          superType.mixins.any(isStruct);
+    }
+    return false;
+  }
+
+  /// Return an indication of the Dart type associated with the [annotation].
+  _PrimitiveDartType _typeForAnnotation(Annotation annotation) {
+    Element element = annotation.element;
+    if (element is ConstructorElement) {
+      String name = element.enclosingElement.name;
+      if (_primitiveIntegerNativeTypes.contains(name)) {
+        return _PrimitiveDartType.int;
+      } else if (_primitiveDoubleNativeTypes.contains(name)) {
+        return _PrimitiveDartType.double;
+      }
+    }
+    return _PrimitiveDartType.none;
+  }
+
+  /// Validate that the [annotations] include exactly one annotation that
+  /// satisfies the [requiredTypes]. If an error is produced that cannot be
+  /// associated with an annotation, associate it with the [errorNode].
+  void _validateAnnotations(AstNode errorNode, NodeList<Annotation> annotations,
+      _PrimitiveDartType requiredType) {
+    bool requiredFound = false;
+    List<Annotation> extraAnnotations = [];
+    for (Annotation annotation in annotations) {
+      if (_isDartFfiElement(annotation.element)) {
+        if (requiredFound) {
+          extraAnnotations.add(annotation);
+        } else {
+          _PrimitiveDartType foundType = _typeForAnnotation(annotation);
+          if (foundType == requiredType) {
+            requiredFound = true;
+          } else {
+            extraAnnotations.add(annotation);
+          }
+        }
+      }
+    }
+    if (extraAnnotations.isNotEmpty) {
+      if (!requiredFound) {
+        Annotation invalidAnnotation = extraAnnotations.removeAt(0);
+        _errorReporter.reportErrorForNode(
+            FfiCode.MISMATCHED_ANNOTATION_ON_STRUCT_FIELD, invalidAnnotation);
+      }
+      for (Annotation extraAnnotation in extraAnnotations) {
+        _errorReporter.reportErrorForNode(
+            FfiCode.EXTRA_ANNOTATION_ON_STRUCT_FIELD, extraAnnotation);
+      }
+    } else if (!requiredFound) {
+      _errorReporter.reportErrorForNode(
+          FfiCode.MISSING_ANNOTATION_ON_STRUCT_FIELD, errorNode);
+    }
+  }
+
+  /// Validate the invocation of the instance method
+  /// `Pointer<T>.asFunction<F>()`.
+  void _validateAsFunction(MethodInvocation node, MethodElement element) {
+    NodeList<TypeAnnotation> typeArguments = node.typeArguments?.arguments;
+    if (typeArguments != null && typeArguments.length == 1) {
+      if (_validateTypeArgument(typeArguments[0], 'asFunction')) {
+        return;
+      }
+    }
+    Expression target = node.realTarget;
+    DartType targetType = target.staticType;
+    if (targetType is InterfaceType &&
+        _isPointer(targetType.element) &&
+        targetType.typeArguments.length == 1) {
+      final DartType T = targetType.typeArguments[0];
+      if (!_isNativeFunctionInterfaceType(T) ||
+          !_isValidFfiNativeFunctionType(
+              (T as InterfaceType).typeArguments.single)) {
+        final AstNode errorNode =
+            typeArguments != null ? typeArguments[0] : node;
+        _errorReporter.reportTypeErrorForNode(
+            FfiCode.NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER,
+            errorNode,
+            [T.displayName]);
+        return;
+      }
+
+      final DartType TPrime = (T as InterfaceType).typeArguments[0];
+      final DartType F = node.typeArgumentTypes[0];
+      if (!_validateCompatibleFunctionTypes(F, TPrime)) {
+        _errorReporter.reportTypeErrorForNode(FfiCode.MUST_BE_A_SUBTYPE, node,
+            [TPrime.displayName, F.displayName, 'asFunction']);
+      }
+    }
+  }
+
+  /// Validate that the fields declared by the given [node] meet the
+  /// requirements for fields within a struct class.
+  void _validateFieldsInStruct(FieldDeclaration node) {
+    if (node.isStatic) {
+      return;
+    }
+    VariableDeclarationList fields = node.fields;
+    NodeList<Annotation> annotations = node.metadata;
+    TypeAnnotation fieldType = fields.type;
+    if (fieldType == null) {
+      _errorReporter.reportErrorForNode(
+          FfiCode.MISSING_FIELD_TYPE_IN_STRUCT, fields.variables[0].name);
+    } else {
+      DartType declaredType = fieldType.type;
+      if (declaredType.isDartCoreInt) {
+        _validateAnnotations(fieldType, annotations, _PrimitiveDartType.int);
+      } else if (declaredType.isDartCoreDouble) {
+        _validateAnnotations(fieldType, annotations, _PrimitiveDartType.double);
+      } else if (_isPointer(declaredType.element)) {
+        _validateNoAnnotations(annotations);
+      } else {
+        _errorReporter.reportErrorForNode(FfiCode.INVALID_FIELD_TYPE_IN_STRUCT,
+            fieldType, [fieldType.toSource()]);
+      }
+    }
+    for (VariableDeclaration field in fields.variables) {
+      if (field.initializer != null) {
+        _errorReporter.reportErrorForNode(
+            FfiCode.FIELD_IN_STRUCT_WITH_INITIALIZER, field.name);
+      }
+    }
+  }
+
+  /// Validate the invocation of the static method
+  /// `Pointer<T>.fromFunction(f, e)`.
+  void _validateFromFunction(MethodInvocation node, MethodElement element) {
+    final int argCount = node.argumentList.arguments.length;
+    if (argCount < 1 || argCount > 2) {
+      // There are other diagnostics reported against the invocation and the
+      // diagnostics generated below might be inaccurate, so don't report them.
+      return;
+    }
+
+    final DartType T = node.typeArgumentTypes[0];
+    if (!_isValidFfiNativeFunctionType(T)) {
+      _errorReporter.reportTypeErrorForNode(
+          FfiCode.MUST_BE_A_NATIVE_FUNCTION_TYPE,
+          node,
+          [T.displayName, 'fromFunction']);
+      return;
+    }
+
+    Expression f = node.argumentList.arguments[0];
+    DartType FT = f.staticType;
+    if (!_validateCompatibleFunctionTypes(FT, T)) {
+      _errorReporter.reportTypeErrorForNode(
+          FfiCode.MUST_BE_A_SUBTYPE, f, [f.staticType, T, 'fromFunction']);
+      return;
+    }
+
+    // TODO(brianwilkerson) Validate that `f` is a top-level function.
+    final DartType R = (T as FunctionType).returnType;
+    if ((FT as FunctionType).returnType.isVoid || _isPointer(R.element)) {
+      if (argCount != 1) {
+        _errorReporter.reportErrorForNode(
+            FfiCode.INVALID_EXCEPTION_VALUE, node.argumentList.arguments[1]);
+      }
+    } else if (argCount != 2) {
+      _errorReporter.reportErrorForNode(
+          FfiCode.MISSING_EXCEPTION_VALUE, node.methodName);
+    } else {
+      Expression e = node.argumentList.arguments[1];
+      // TODO(brianwilkerson) Validate that `e` is a constant expression.
+      if (!_validateCompatibleNativeType(e.staticType, R, true)) {
+        _errorReporter.reportTypeErrorForNode(
+            FfiCode.MUST_BE_A_SUBTYPE, e, [e.staticType, R, 'fromFunction']);
+      }
+    }
+  }
+
+  /// Validate the invocation of the instance method
+  /// `DynamicLibrary.lookupFunction<S, F>()`.
+  void _validateLookupFunction(MethodInvocation node) {
+    final NodeList<TypeAnnotation> typeArguments =
+        node.typeArguments?.arguments;
+    if (typeArguments?.length != 2) {
+      // There are other diagnostics reported against the invocation and the
+      // diagnostics generated below might be inaccurate, so don't report them.
+      return;
+    }
+
+    final List<DartType> argTypes = node.typeArgumentTypes;
+    final DartType S = argTypes[0];
+    final DartType F = argTypes[1];
+    if (!_isValidFfiNativeFunctionType(S)) {
+      final AstNode errorNode = typeArguments[0];
+      _errorReporter.reportTypeErrorForNode(
+          FfiCode.MUST_BE_A_NATIVE_FUNCTION_TYPE,
+          errorNode,
+          [S.displayName, 'lookupFunction']);
+      return;
+    }
+    if (!_validateCompatibleFunctionTypes(F, S)) {
+      final AstNode errorNode = typeArguments[1];
+      _errorReporter.reportTypeErrorForNode(FfiCode.MUST_BE_A_SUBTYPE,
+          errorNode, [S.displayName, F.displayName, 'lookupFunction']);
+    }
+  }
+
+  /// Validate that none of the [annotations] are from `dart:ffi`.
+  void _validateNoAnnotations(NodeList<Annotation> annotations) {
+    for (Annotation annotation in annotations) {
+      if (_isDartFfiElement(annotation.element)) {
+        _errorReporter.reportErrorForNode(
+            FfiCode.ANNOTATION_ON_POINTER_FIELD, annotation);
+      }
+    }
+  }
+
+  /// Validate that the given [typeArgument] has a constant value. Return `true`
+  /// if a diagnostic was produced because it isn't constant.
+  bool _validateTypeArgument(TypeAnnotation typeArgument, String functionName) {
+    if (typeArgument.type is TypeParameterType) {
+      _errorReporter.reportErrorForNode(
+          FfiCode.NON_CONSTANT_TYPE_ARGUMENT, typeArgument, [functionName]);
+      return true;
+    }
+    return false;
+  }
+
+  /// Validates that the given [nativeType] is, when native types are converted
+  /// to their Dart equivalent, a subtype of [dartType].
+  bool _validateCompatibleFunctionTypes(
+      DartType dartType, DartType nativeType) {
+    // We require both to be valid function types.
+    if (dartType is! FunctionType ||
+        dartType.isDartCoreFunction ||
+        nativeType is! FunctionType ||
+        nativeType.isDartCoreFunction) {
+      return false;
+    }
+
+    final dartFType = dartType as FunctionType;
+    final nativeFType = nativeType as FunctionType;
+
+    // We disallow any optional parameters.
+    final int parameterCount = dartFType.normalParameterTypes.length;
+    if (parameterCount != nativeFType.normalParameterTypes.length) {
+      return false;
+    }
+    // We disallow generic function types.
+    if (dartFType.typeFormals.isNotEmpty ||
+        nativeFType.typeFormals.isNotEmpty) {
+      return false;
+    }
+    if (dartFType.namedParameterTypes.isNotEmpty ||
+        dartFType.optionalParameterTypes.isNotEmpty ||
+        nativeFType.namedParameterTypes.isNotEmpty ||
+        nativeFType.optionalParameterTypes.isNotEmpty) {
+      return false;
+    }
+
+    // Validate that the return types are compatible.
+    if (!_validateCompatibleNativeType(
+        dartFType.returnType, nativeFType.returnType, false)) {
+      return false;
+    }
+
+    // Validate that the parameter types are compatible.
+    for (int i = 0; i < parameterCount; ++i) {
+      if (!_validateCompatibleNativeType(dartFType.normalParameterTypes[i],
+          nativeFType.normalParameterTypes[i], true)) {
+        return false;
+      }
+    }
+
+    // Signatures have same number of parameters and the types match.
+    return true;
+  }
+
+  // Validates that, if we convert [nativeType] to it's corresponding
+  // [dartType] the latter is a subtype of the former if
+  // [checkCovariance].
+  bool _validateCompatibleNativeType(
+      DartType dartType, DartType nativeType, bool checkCovariance) {
+    final nativeReturnType = _primitiveNativeType(nativeType);
+    if (nativeReturnType == _PrimitiveDartType.int) {
+      return dartType.isDartCoreInt;
+    } else if (nativeReturnType == _PrimitiveDartType.double) {
+      return dartType.isDartCoreDouble;
+    } else if (nativeReturnType == _PrimitiveDartType.void_) {
+      return dartType.isVoid;
+    } else if (dartType is InterfaceType && nativeType is InterfaceType) {
+      return checkCovariance
+          ? typeSystem.isSubtypeOf(dartType, nativeType)
+          : typeSystem.isSubtypeOf(nativeType, dartType);
+    } else {
+      // If the [nativeType] is not a primitive int/double type then it has to
+      // be a Pointer type atm.
+      return false;
+    }
+  }
+
+  // Validates that the given type is a valid dart:ffi native function
+  // signature.
+  bool _isValidFfiNativeFunctionType(DartType nativeType) {
+    if (nativeType is FunctionType && !nativeType.isDartCoreFunction) {
+      if (nativeType.namedParameterTypes.isNotEmpty ||
+          nativeType.optionalParameterTypes.isNotEmpty) {
+        return false;
+      }
+      if (!_isValidFfiNativeType(nativeType.returnType, true)) {
+        return false;
+      }
+
+      for (final DartType typeArg in nativeType.typeArguments) {
+        if (!_isValidFfiNativeType(typeArg, false)) {
+          return false;
+        }
+      }
+      return true;
+    }
+    return false;
+  }
+
+  // Validates that the given [nativeType] is a valid dart:ffi native type.
+  bool _isValidFfiNativeType(DartType nativeType, bool allowVoid) {
+    if (nativeType is InterfaceType) {
+      // Is it a primitive integer/double type (or ffi.Void if we allow it).
+      final primitiveType = _primitiveNativeType(nativeType);
+      if (primitiveType != _PrimitiveDartType.none &&
+          (primitiveType != _PrimitiveDartType.void_ || allowVoid)) {
+        return true;
+      }
+      if (_isNativeFunctionInterfaceType(nativeType)) {
+        return _isValidFfiNativeFunctionType(nativeType.typeArguments.single);
+      }
+      if (_isPointerInterfaceType(nativeType)) {
+        final nativeArgumentType = nativeType.typeArguments.single;
+        return _isValidFfiNativeType(nativeArgumentType, true) ||
+            _isStructClass(nativeArgumentType);
+      }
+    } else if (nativeType is FunctionType) {
+      return _isValidFfiNativeFunctionType(nativeType);
+    }
+    return false;
+  }
+
+  _PrimitiveDartType _primitiveNativeType(DartType nativeType) {
+    if (nativeType is InterfaceType) {
+      final element = nativeType.element;
+      if (element.library.name == 'dart.ffi') {
+        final String name = element.name;
+        if (_primitiveIntegerNativeTypes.contains(name)) {
+          return _PrimitiveDartType.int;
+        }
+        if (_primitiveDoubleNativeTypes.contains(name)) {
+          return _PrimitiveDartType.double;
+        }
+        if (name == 'Void') {
+          return _PrimitiveDartType.void_;
+        }
+      }
+    }
+    return _PrimitiveDartType.none;
+  }
+
+  // Returns `true` iff [nativeType] is a `ffi.NativeFunction<???>` type.
+  bool _isNativeFunctionInterfaceType(DartType nativeType) {
+    if (nativeType is InterfaceType) {
+      final element = nativeType.element;
+      if (element.library.name == 'dart.ffi') {
+        return element.name == 'NativeFunction' &&
+            nativeType.typeArguments?.length == 1;
+      }
+    }
+    return false;
+  }
+
+  // Returns `true` iff [nativeType] is a `ffi.Pointer<???>` type.
+  bool _isPointerInterfaceType(DartType nativeType) {
+    if (nativeType is InterfaceType) {
+      final element = nativeType.element;
+      if (element.library.name == 'dart.ffi') {
+        return element.name == 'Pointer' &&
+            nativeType.typeArguments?.length == 1;
+      }
+    }
+    return false;
+  }
+
+  // Returns `true` iff [nativeType] is a struct type.
+  _isStructClass(DartType nativeType) {
+    if (nativeType is InterfaceType) {
+      final superClassElement = nativeType.element.supertype.element;
+      if (superClassElement.library.name == 'dart.ffi') {
+        return superClassElement.name == 'Struct' &&
+            nativeType.typeArguments?.isEmpty == true;
+      }
+    }
+    return false;
+  }
+
+  static const List<String> _primitiveIntegerNativeTypes = [
+    'Int8',
+    'Int16',
+    'Int32',
+    'Int64',
+    'Uint8',
+    'Uint16',
+    'Uint32',
+    'Uint64',
+    'IntPtr'
+  ];
+
+  static const List<String> _primitiveDoubleNativeTypes = [
+    'Float',
+    'Double',
+  ];
+}
+
+enum _PrimitiveDartType {
+  double,
+  int,
+  void_,
+  none,
+}
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index c0e84af..4fbbf74 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -233,7 +233,7 @@
 
   @override
   void visitClassDeclaration(ClassDeclaration node) {
-    var element = AbstractClassElementImpl.getImpl(node.declaredElement);
+    ClassElementImpl element = node.declaredElement;
     _enclosingClass = element;
     _invalidAccessVerifier._enclosingClass = element;
 
@@ -3476,9 +3476,10 @@
       node.accept(elementResolver);
     } else if (operator == TokenType.BANG_EQ || operator == TokenType.EQ_EQ) {
       left.accept(this);
+      _flowAnalysis?.flow?.equalityOp_rightBegin(left);
       right.accept(this);
       node.accept(elementResolver);
-      _flowAnalysis?.binaryExpression_equal(node, left, right,
+      _flowAnalysis?.flow?.equalityOp_end(node, right,
           notEqual: operator == TokenType.BANG_EQ);
     } else {
       if (operator == TokenType.QUESTION_QUESTION) {
@@ -3523,12 +3524,10 @@
   @override
   void visitBlockFunctionBody(BlockFunctionBody node) {
     try {
-      _flowAnalysis?.functionBody_enter(node);
       inferenceContext.pushReturnContext(node);
       super.visitBlockFunctionBody(node);
     } finally {
       inferenceContext.popReturnContext(node);
-      _flowAnalysis?.functionBody_exit(node);
     }
   }
 
@@ -3664,12 +3663,17 @@
   void visitConstructorDeclaration(ConstructorDeclaration node) {
     ExecutableElement outerFunction = _enclosingFunction;
     try {
+      _flowAnalysis?.topLevelDeclaration_enter(
+          node, node.parameters, node.body);
+      _flowAnalysis?.executableDeclaration_enter(node, node.parameters, false);
       _promoteManager.enterFunctionBody(node.body);
       _enclosingFunction = node.declaredElement;
       FunctionType type = _enclosingFunction.type;
       InferenceContext.setType(node.body, type.returnType);
       super.visitConstructorDeclaration(node);
     } finally {
+      _flowAnalysis?.executableDeclaration_exit(node.body, false);
+      _flowAnalysis?.topLevelDeclaration_exit();
       _promoteManager.exitFunctionBody();
       _enclosingFunction = outerFunction;
     }
@@ -3754,9 +3758,9 @@
     InferenceContext.setType(node.condition, typeProvider.boolType);
 
     _flowAnalysis?.flow?.doStatement_bodyBegin(
-      node,
-      _flowAnalysis.assignedVariables.writtenInNode(node),
-    );
+        node,
+        _flowAnalysis.assignedVariables.writtenInNode(node),
+        _flowAnalysis.assignedVariables.capturedInNode(node));
     visitStatementInScope(body);
 
     _flowAnalysis?.flow?.doStatement_conditionBegin();
@@ -3807,7 +3811,6 @@
       return;
     }
     try {
-      _flowAnalysis?.functionBody_enter(node);
       InferenceContext.setTypeFromNode(node.expression, node);
       inferenceContext.pushReturnContext(node);
       super.visitExpressionFunctionBody(node);
@@ -3821,7 +3824,6 @@
       }
     } finally {
       inferenceContext.popReturnContext(node);
-      _flowAnalysis?.functionBody_exit(node);
     }
   }
 
@@ -3914,6 +3916,7 @@
       loopVariable?.accept(this);
       _flowAnalysis?.flow?.forEach_bodyBegin(
           _flowAnalysis.assignedVariables.writtenInNode(node),
+          _flowAnalysis.assignedVariables.capturedInNode(node),
           identifierElement is VariableElement
               ? identifierElement
               : loopVariable.declaredElement);
@@ -3994,9 +3997,10 @@
 
       _flowAnalysis?.flow?.forEach_bodyBegin(
           _flowAnalysis.assignedVariables.writtenInNode(node),
+          _flowAnalysis.assignedVariables.capturedInNode(node),
           identifierElement is VariableElement
               ? identifierElement
-              : loopVariable.declaredElement);
+              : loopVariable?.declaredElement);
 
       Statement body = node.body;
       if (body != null) {
@@ -4013,14 +4017,36 @@
   @override
   void visitFunctionDeclaration(FunctionDeclaration node) {
     ExecutableElement outerFunction = _enclosingFunction;
+    bool isFunctionDeclarationStatement =
+        node.parent is FunctionDeclarationStatement;
     try {
       SimpleIdentifier functionName = node.name;
+      if (_flowAnalysis != null) {
+        if (isFunctionDeclarationStatement) {
+          _flowAnalysis.flow.functionExpression_begin(
+              _flowAnalysis.assignedVariables.writtenInNode(node));
+        } else {
+          _flowAnalysis.topLevelDeclaration_enter(node,
+              node.functionExpression.parameters, node.functionExpression.body);
+        }
+        _flowAnalysis.executableDeclaration_enter(node,
+            node.functionExpression.parameters, isFunctionDeclarationStatement);
+      }
       _promoteManager.enterFunctionBody(node.functionExpression.body);
       _enclosingFunction = functionName.staticElement as ExecutableElement;
       InferenceContext.setType(
           node.functionExpression, _enclosingFunction.type);
       super.visitFunctionDeclaration(node);
     } finally {
+      if (_flowAnalysis != null) {
+        _flowAnalysis.executableDeclaration_exit(
+            node.functionExpression.body, isFunctionDeclarationStatement);
+        if (isFunctionDeclarationStatement) {
+          _flowAnalysis.flow.functionExpression_end();
+        } else {
+          _flowAnalysis.topLevelDeclaration_exit();
+        }
+      }
       _promoteManager.exitFunctionBody();
       _enclosingFunction = outerFunction;
     }
@@ -4035,9 +4061,13 @@
   @override
   void visitFunctionExpression(FunctionExpression node) {
     ExecutableElement outerFunction = _enclosingFunction;
+    bool isFunctionDeclaration = node.parent is FunctionDeclaration;
     try {
       if (_flowAnalysis != null) {
-        _flowAnalysis.flow?.functionExpression_begin();
+        if (!isFunctionDeclaration) {
+          _flowAnalysis.flow.functionExpression_begin(
+              _flowAnalysis.assignedVariables.writtenInNode(node));
+        }
       } else {
         _promoteManager.enterFunctionBody(node.body);
       }
@@ -4056,7 +4086,9 @@
       super.visitFunctionExpression(node);
     } finally {
       if (_flowAnalysis != null) {
-        _flowAnalysis.flow?.functionExpression_end();
+        if (!isFunctionDeclaration) {
+          _flowAnalysis.flow?.functionExpression_end();
+        }
       } else {
         _promoteManager.exitFunctionBody();
       }
@@ -4222,6 +4254,9 @@
   void visitMethodDeclaration(MethodDeclaration node) {
     ExecutableElement outerFunction = _enclosingFunction;
     try {
+      _flowAnalysis?.topLevelDeclaration_enter(
+          node, node.parameters, node.body);
+      _flowAnalysis?.executableDeclaration_enter(node, node.parameters, false);
       _promoteManager.enterFunctionBody(node.body);
       _enclosingFunction = node.declaredElement;
       DartType returnType =
@@ -4229,6 +4264,8 @@
       InferenceContext.setType(node.body, returnType);
       super.visitMethodDeclaration(node);
     } finally {
+      _flowAnalysis?.executableDeclaration_exit(node.body, false);
+      _flowAnalysis?.topLevelDeclaration_exit();
       _promoteManager.exitFunctionBody();
       _enclosingFunction = outerFunction;
     }
@@ -4299,9 +4336,25 @@
   }
 
   @override
+  void visitNullLiteral(NullLiteral node) {
+    _flowAnalysis?.flow?.nullLiteral(node);
+    super.visitNullLiteral(node);
+  }
+
+  @override
   void visitParenthesizedExpression(ParenthesizedExpression node) {
     InferenceContext.setTypeFromNode(node.expression, node);
     super.visitParenthesizedExpression(node);
+    _flowAnalysis?.flow?.parenthesizedExpression(node, node.expression);
+  }
+
+  @override
+  void visitPostfixExpression(PostfixExpression node) {
+    super.visitPostfixExpression(node);
+
+    if (node.operator.type == TokenType.BANG) {
+      _flowAnalysis?.flow?.nonNullAssert_end(node.operand);
+    }
   }
 
   @override
@@ -4479,6 +4532,8 @@
         var flow = _flowAnalysis.flow;
         var assignedInCases =
             _flowAnalysis.assignedVariables.writtenInNode(node);
+        var capturedInCases =
+            _flowAnalysis.assignedVariables.capturedInNode(node);
 
         flow.switchStatement_expressionEnd(node);
 
@@ -4486,9 +4541,7 @@
         var members = node.members;
         for (var member in members) {
           flow.switchStatement_beginCase(
-            member.labels.isNotEmpty,
-            assignedInCases,
-          );
+              member.labels.isNotEmpty, assignedInCases, capturedInCases);
           member.accept(this);
 
           if (member is SwitchDefault) {
@@ -4531,18 +4584,18 @@
     flow.tryCatchStatement_bodyBegin();
     body.accept(this);
     flow.tryCatchStatement_bodyEnd(
-      _flowAnalysis.assignedVariables.writtenInNode(body),
-    );
+        _flowAnalysis.assignedVariables.writtenInNode(body),
+        _flowAnalysis.assignedVariables.capturedInNode(body));
 
     var catchLength = catchClauses.length;
     for (var i = 0; i < catchLength; ++i) {
       var catchClause = catchClauses[i];
       flow.tryCatchStatement_catchBegin();
       if (catchClause.exceptionParameter != null) {
-        flow.write(catchClause.exceptionParameter.staticElement);
+        flow.initialize(catchClause.exceptionParameter.staticElement);
       }
       if (catchClause.stackTraceParameter != null) {
-        flow.write(catchClause.stackTraceParameter.staticElement);
+        flow.initialize(catchClause.stackTraceParameter.staticElement);
       }
       catchClause.accept(this);
       flow.tryCatchStatement_catchEnd();
@@ -4552,8 +4605,8 @@
 
     if (finallyBlock != null) {
       flow.tryFinallyStatement_finallyBegin(
-        _flowAnalysis.assignedVariables.writtenInNode(body),
-      );
+          _flowAnalysis.assignedVariables.writtenInNode(body),
+          _flowAnalysis.assignedVariables.capturedInNode(body));
       finallyBlock.accept(this);
       flow.tryFinallyStatement_end(
         _flowAnalysis.assignedVariables.writtenInNode(finallyBlock),
@@ -4566,12 +4619,21 @@
 
   @override
   void visitVariableDeclaration(VariableDeclaration node) {
+    var grandParent = node.parent.parent;
+    bool isTopLevel = grandParent is FieldDeclaration ||
+        grandParent is TopLevelVariableDeclaration;
     InferenceContext.setTypeFromNode(node.initializer, node);
+    if (isTopLevel) {
+      _flowAnalysis?.topLevelDeclaration_enter(node, null, null);
+    }
     super.visitVariableDeclaration(node);
+    if (isTopLevel) {
+      _flowAnalysis?.topLevelDeclaration_exit();
+    }
     VariableElement element = node.declaredElement;
     if (element.initializer != null && node.initializer != null) {
-      (element.initializer as FunctionElementImpl).returnType =
-          node.initializer.staticType;
+      var initializer = element.initializer as FunctionElementImpl;
+      initializer.returnType = node.initializer.staticType;
     }
     // Note: in addition to cloning the initializers for const variables, we
     // have to clone the initializers for non-static final fields (because if
@@ -4607,8 +4669,8 @@
       InferenceContext.setType(condition, typeProvider.boolType);
 
       _flowAnalysis?.flow?.whileStatement_conditionBegin(
-        _flowAnalysis.assignedVariables.writtenInNode(node),
-      );
+          _flowAnalysis.assignedVariables.writtenInNode(node),
+          _flowAnalysis.assignedVariables.capturedInNode(node));
       condition?.accept(this);
 
       Statement body = node.body;
@@ -5919,6 +5981,13 @@
 
   Scope nameScope;
 
+  /// If [resolveTypeName] finds out that the given [TypeName] with a
+  /// [PrefixedIdentifier] name is actually the name of a class and the name of
+  /// the constructor, it rewrites the [ConstructorName] to correctly represent
+  /// the type and the constructor name, and set this field to the rewritten
+  /// [ConstructorName]. Otherwise this field will be set `null`.
+  ConstructorName rewriteResult;
+
   TypeNameResolver(
       this.typeSystem,
       TypeProvider typeProvider,
@@ -5951,6 +6020,7 @@
   ///
   /// The client must set [nameScope] before calling [resolveTypeName].
   void resolveTypeName(TypeName node) {
+    rewriteResult = null;
     Identifier typeName = node.name;
     _setElement(typeName, null); // Clear old Elements from previous run.
     TypeArgumentList argumentList = node.typeArguments;
@@ -6029,6 +6099,7 @@
             name.period = prefixedIdentifier.period;
             node.name = prefix;
             typeName = prefix;
+            rewriteResult = parent;
           }
         }
       }
@@ -6139,6 +6210,7 @@
             element = prefixElement;
             argumentList = null;
             elementValid = true;
+            rewriteResult = newConstructorName;
           }
         } else {
           reportErrorForNode(
@@ -7176,7 +7248,6 @@
           new CaughtException(new AnalysisException(), null));
     }
     element.declaredReturnType = _computeReturnType(node.returnType);
-    element.type = new FunctionTypeImpl(element);
     _inferSetterReturnType(element);
   }
 
@@ -7247,7 +7318,6 @@
     }
 
     element.declaredReturnType = _computeReturnType(node.returnType);
-    element.type = new FunctionTypeImpl(element);
     _inferSetterReturnType(element);
     _inferOperatorReturnType(element);
     if (element is PropertyAccessorElement) {
diff --git a/pkg/analyzer/lib/src/generated/sdk.dart b/pkg/analyzer/lib/src/generated/sdk.dart
index f981dcf..1db0d80 100644
--- a/pkg/analyzer/lib/src/generated/sdk.dart
+++ b/pkg/analyzer/lib/src/generated/sdk.dart
@@ -324,22 +324,12 @@
   static String _VM_PLATFORM = "VM_PLATFORM";
 
   /**
-   * A flag indicating whether the dart2js path should be used when it is
-   * available.
-   */
-  final bool _useDart2jsPaths;
-
-  /**
    * The library map that is populated by visiting the AST structure parsed from
    * the contents of the libraries file.
    */
   LibraryMap _librariesMap = new LibraryMap();
 
-  /**
-   * Initialize a newly created library builder to use the dart2js path if
-   * [_useDart2jsPaths] is `true`.
-   */
-  SdkLibrariesReader_LibraryBuilder(this._useDart2jsPaths);
+  SdkLibrariesReader_LibraryBuilder([@deprecated bool useDart2jsPaths]);
 
   /**
    * Return the library map that was populated by visiting the AST structure
@@ -398,7 +388,7 @@
                 library.setDart2JsLibrary();
               }
             }
-          } else if (_useDart2jsPaths && name == _DART2JS_PATH) {
+          } else if (name == _DART2JS_PATH) {
             if (expression is SimpleStringLiteral) {
               library.path = expression.value;
             }
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 260c049..974ae86 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -545,12 +545,14 @@
       // we only need to handle local functions.
       if (node.returnType == null) {
         _inferLocalFunctionReturnType(node.functionExpression);
+        _recordStaticTypeWhereItShouldNotBe(node.name, functionElement.type);
         return;
       }
       functionElement.returnType =
           _computeStaticReturnTypeOfFunctionDeclaration(node);
     }
     _recordStaticType(function, functionElement.type);
+    _recordStaticTypeWhereItShouldNotBe(node.name, functionElement.type);
   }
 
   /**
@@ -2049,6 +2051,11 @@
     }
   }
 
+  /// Remove when https://dart-review.googlesource.com/c/sdk/+/119761 lands.
+  void _recordStaticTypeWhereItShouldNotBe(Expression node, DartType type) {
+    node.staticType = type;
+  }
+
   void _setExtensionIdentifierType(Identifier node) {
     if (node is SimpleIdentifier && node.inDeclarationContext()) {
       return;
diff --git a/pkg/analyzer/lib/src/generated/testing/element_factory.dart b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
index 94530e8..846783b 100644
--- a/pkg/analyzer/lib/src/generated/testing/element_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
@@ -274,8 +274,6 @@
     // We don't create parameter elements because we don't have parameter names
     FunctionElementImpl functionElement =
         new FunctionElementImpl(functionName, 0);
-    FunctionTypeImpl functionType = new FunctionTypeImpl(functionElement);
-    functionElement.type = functionType;
     functionElement.returnType = returnType ?? VoidTypeImpl.instance;
     // parameters
     int normalCount = normalParameters == null ? 0 : normalParameters.length;
@@ -308,8 +306,6 @@
       List<ClassElement> namedParameters) {
     FunctionElementImpl functionElement =
         new FunctionElementImpl(functionName, 0);
-    FunctionTypeImpl functionType = new FunctionTypeImpl(functionElement);
-    functionElement.type = functionType;
     // parameters
     int normalCount = normalParameters == null ? 0 : normalParameters.length;
     int nameCount = names == null ? 0 : names.length;
@@ -405,8 +401,6 @@
     functionElement.returnType =
         returnType == null ? VoidTypeImpl.instance : returnType;
     functionElement.parameters = parameters;
-    FunctionTypeImpl functionType = new FunctionTypeImpl(functionElement);
-    functionElement.type = functionType;
     return functionElement;
   }
 
@@ -434,8 +428,6 @@
     getter.returnType = type;
     getter.isStatic = isStatic;
     field.getter = getter;
-    FunctionTypeImpl getterType = new FunctionTypeImpl(getter);
-    getter.type = getterType;
     return getter;
   }
 
@@ -482,8 +474,6 @@
       method.parameters = parameters;
     }
     method.returnType = returnType;
-    FunctionTypeImpl methodType = new FunctionTypeImpl(method);
-    method.type = methodType;
     return method;
   }
 
@@ -496,7 +486,6 @@
     method.enclosingElement = enclosingElement;
     method.parameters = parameters;
     method.returnType = returnType;
-    method.type = new FunctionTypeImpl(method);
     return method;
   }
 
@@ -586,8 +575,6 @@
     getter.variable = field;
     getter.returnType = type;
     field.getter = getter;
-    FunctionTypeImpl getterType = new FunctionTypeImpl(getter);
-    getter.type = getterType;
     ParameterElementImpl parameter = requiredParameter2("a", type);
     PropertyAccessorElementImpl setter =
         new PropertyAccessorElementImpl(name, -1);
@@ -596,7 +583,6 @@
     setter.variable = field;
     setter.parameters = <ParameterElement>[parameter];
     setter.returnType = VoidTypeImpl.instance;
-    setter.type = new FunctionTypeImpl(setter);
     setter.isStatic = isStatic;
     field.setter = setter;
     return setter;
diff --git a/pkg/analyzer/lib/src/summary2/ast_resolver.dart b/pkg/analyzer/lib/src/summary2/ast_resolver.dart
index 63c1eda..3914139 100644
--- a/pkg/analyzer/lib/src/summary2/ast_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/ast_resolver.dart
@@ -6,49 +6,59 @@
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
-import 'package:analyzer/src/dart/resolver/ast_rewrite.dart';
+import 'package:analyzer/src/dart/resolver/resolution_visitor.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/summary2/link.dart';
 
 /// Used to resolve some AST nodes - variable initializers, and annotations.
 class AstResolver {
   final Linker _linker;
-  final LibraryElement _library;
+  final CompilationUnitElement _unitElement;
   final Scope _nameScope;
 
-  AstResolver(this._linker, this._library, this._nameScope);
+  AstResolver(this._linker, this._unitElement, this._nameScope);
 
   void resolve(
-    AstNode node, {
+    AstNode node,
+    AstNode getNode(), {
     ClassElement enclosingClassElement,
     ExecutableElement enclosingExecutableElement,
     FunctionBody enclosingFunctionBody,
   }) {
     var featureSet = node.thisOrAncestorOfType<CompilationUnit>().featureSet;
-    var source = _FakeSource();
     var errorListener = AnalysisErrorListener.NULL_LISTENER;
 
-    var typeResolverVisitor = new TypeResolverVisitor(
-        _library, source, _linker.typeProvider, errorListener,
-        featureSet: featureSet, nameScope: _nameScope);
-    node.accept(typeResolverVisitor);
-
-    var variableResolverVisitor = new VariableResolverVisitor(
-        _library, source, _linker.typeProvider, errorListener,
-        nameScope: _nameScope, localVariableInfo: LocalVariableInfo());
-    node.accept(variableResolverVisitor);
-
-//    if (_linker.getAst != null) {
-//      expression.accept(_partialResolverVisitor);
-//    }
-
-    var resolverVisitor = new ResolverVisitor(_linker.inheritance, _library,
-        source, _linker.typeProvider, errorListener,
+    node.accept(
+      ResolutionVisitor(
+        unitElement: _unitElement,
         featureSet: featureSet,
         nameScope: _nameScope,
-        propagateTypes: false,
-        reportConstEvaluationErrors: false);
+        errorListener: errorListener,
+      ),
+    );
+    node = getNode();
+
+    var variableResolverVisitor = new VariableResolverVisitor(
+      _unitElement.library,
+      _unitElement.source,
+      _linker.typeProvider,
+      errorListener,
+      nameScope: _nameScope,
+      localVariableInfo: LocalVariableInfo(),
+    );
+    node.accept(variableResolverVisitor);
+
+    var resolverVisitor = new ResolverVisitor(
+      _linker.inheritance,
+      _unitElement.library,
+      _unitElement.source,
+      _linker.typeProvider,
+      errorListener,
+      featureSet: featureSet,
+      nameScope: _nameScope,
+      propagateTypes: false,
+      reportConstEvaluationErrors: false,
+    );
     resolverVisitor.prepareEnclosingDeclarations(
       enclosingClassElement: enclosingClassElement,
       enclosingExecutableElement: enclosingExecutableElement,
@@ -59,22 +69,4 @@
 
     node.accept(resolverVisitor);
   }
-
-  void rewriteAst(AstNode node) {
-    var source = _FakeSource();
-    var errorListener = AnalysisErrorListener.NULL_LISTENER;
-
-    var astRewriteVisitor = new AstRewriteVisitor(_linker.typeSystem, _library,
-        source, _linker.typeProvider, errorListener,
-        nameScope: _nameScope);
-    node.accept(astRewriteVisitor);
-  }
-}
-
-class _FakeSource implements Source {
-  @override
-  String get fullName => '/package/lib/test.dart';
-
-  @override
-  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
 }
diff --git a/pkg/analyzer/lib/src/summary2/constructor_initializer_resolver.dart b/pkg/analyzer/lib/src/summary2/constructor_initializer_resolver.dart
index 4a6d796..2f7d62e 100644
--- a/pkg/analyzer/lib/src/summary2/constructor_initializer_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/constructor_initializer_resolver.dart
@@ -4,7 +4,6 @@
 
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
-import 'package:analyzer/src/dart/element/builder.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/resolver/scope.dart';
 import 'package:analyzer/src/generated/resolver.dart';
@@ -48,7 +47,7 @@
       constructorElement,
     );
 
-    _astResolver = AstResolver(_linker, _libraryElement, initializerScope);
+    _astResolver = AstResolver(_linker, _unitElement, initializerScope);
 
     FunctionBodyImpl body = _constructorNode.body;
     body.localVariableInfo = LocalVariableInfo();
@@ -66,13 +65,10 @@
       return;
     }
 
-    var holder = ElementHolder();
-    var elementBuilder = LocalElementBuilder(holder, _unitElement);
-    initializers.accept(elementBuilder);
-
     for (var initializer in initializers) {
       _astResolver.resolve(
         initializer,
+        () => initializer,
         enclosingClassElement: _classElement,
         enclosingExecutableElement: _constructorElement,
         enclosingFunctionBody: _constructorNode.body,
@@ -85,6 +81,7 @@
     if (redirected != null) {
       _astResolver.resolve(
         redirected,
+        () => redirected,
         enclosingClassElement: _classElement,
         enclosingExecutableElement: _constructorElement,
       );
diff --git a/pkg/analyzer/lib/src/summary2/default_value_resolver.dart b/pkg/analyzer/lib/src/summary2/default_value_resolver.dart
index 728005e..680b212 100644
--- a/pkg/analyzer/lib/src/summary2/default_value_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/default_value_resolver.dart
@@ -5,7 +5,6 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/dart/element/builder.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type_algebra.dart';
 import 'package:analyzer/src/dart/resolver/scope.dart';
@@ -19,6 +18,7 @@
   final LibraryElementImpl _libraryElement;
 
   ClassElement _classElement;
+  CompilationUnitElement _unitElement;
   ExecutableElement _executableElement;
   Scope _scope;
 
@@ -28,6 +28,8 @@
 
   void resolve() {
     for (CompilationUnitElementImpl unit in _libraryElement.units) {
+      _unitElement = unit;
+
       for (var extensionElement in unit.extensions) {
         _extension(extensionElement);
       }
@@ -95,24 +97,20 @@
   }
 
   void _parameter(ParameterElementImpl parameter) {
-    Expression defaultValue;
-    var node = parameter.linkedNode;
-    if (node is DefaultFormalParameter) {
-      defaultValue = node.defaultValue;
-    }
-    if (defaultValue == null) return;
-
-    var holder = ElementHolder();
-    defaultValue.accept(LocalElementBuilder(holder, null));
-    parameter.encloseElements(holder.localVariables);
+    var node = _defaultParameter(parameter);
+    if (node == null) return;
 
     var contextType = TypeVariableEliminator(_linker.typeProvider)
         .substituteType(parameter.type);
-    InferenceContext.setType(defaultValue, contextType);
 
-    _astResolver ??= AstResolver(_linker, _libraryElement, _scope);
+    _astResolver ??= AstResolver(_linker, _unitElement, _scope);
     _astResolver.resolve(
-      defaultValue,
+      node.defaultValue,
+      () {
+        var defaultValue = node.defaultValue;
+        InferenceContext.setType(defaultValue, contextType);
+        return defaultValue;
+      },
       enclosingClassElement: _classElement,
       enclosingExecutableElement: _executableElement,
     );
@@ -127,6 +125,16 @@
   void _setScopeFromElement(Element element) {
     _scope = LinkingNodeContext.get((element as ElementImpl).linkedNode).scope;
   }
+
+  static DefaultFormalParameter _defaultParameter(
+      ParameterElementImpl element) {
+    var node = element.linkedNode;
+    if (node is DefaultFormalParameter && node.defaultValue != null) {
+      return node;
+    } else {
+      return null;
+    }
+  }
 }
 
 class TypeVariableEliminator extends Substitution {
diff --git a/pkg/analyzer/lib/src/summary2/library_builder.dart b/pkg/analyzer/lib/src/summary2/library_builder.dart
index f02bc83..19737c5 100644
--- a/pkg/analyzer/lib/src/summary2/library_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/library_builder.dart
@@ -246,7 +246,7 @@
 
   void resolveMetadata() {
     for (CompilationUnitElementImpl unit in element.units) {
-      var resolver = MetadataResolver(linker, element, scope, unit);
+      var resolver = MetadataResolver(linker, scope, unit);
       unit.linkedNode.accept(resolver);
     }
   }
diff --git a/pkg/analyzer/lib/src/summary2/metadata_resolver.dart b/pkg/analyzer/lib/src/summary2/metadata_resolver.dart
index 5d77644..7f3a04b 100644
--- a/pkg/analyzer/lib/src/summary2/metadata_resolver.dart
+++ b/pkg/analyzer/lib/src/summary2/metadata_resolver.dart
@@ -5,7 +5,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/src/dart/element/builder.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/summary2/ast_resolver.dart';
@@ -14,25 +13,19 @@
 
 class MetadataResolver extends ThrowingAstVisitor<void> {
   final Linker _linker;
-  final LibraryElement _libraryElement;
   final Scope _libraryScope;
   final CompilationUnitElement _unitElement;
   Scope _scope;
 
-  MetadataResolver(
-      this._linker, this._libraryElement, this._libraryScope, this._unitElement)
+  MetadataResolver(this._linker, this._libraryScope, this._unitElement)
       : _scope = _libraryScope;
 
   @override
   void visitAnnotation(Annotation node) {
     node.elementAnnotation = ElementAnnotationImpl(_unitElement);
 
-    var holder = ElementHolder();
-    node.accept(LocalElementBuilder(holder, null));
-
-    var astResolver = AstResolver(_linker, _libraryElement, _scope);
-    astResolver.rewriteAst(node);
-    astResolver.resolve(node);
+    var astResolver = AstResolver(_linker, _unitElement, _scope);
+    astResolver.resolve(node, () => node);
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/summary2/top_level_inference.dart b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
index 76b23f9..d4b7b0c 100644
--- a/pkg/analyzer/lib/src/summary2/top_level_inference.dart
+++ b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
@@ -6,7 +6,6 @@
 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/element/builder.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';
@@ -39,6 +38,7 @@
 class ConstantInitializersResolver {
   final Linker linker;
 
+  CompilationUnitElement _unitElement;
   LibraryElement _library;
   bool _enclosingClassHasConstConstructor = false;
   Scope _scope;
@@ -49,6 +49,7 @@
     for (var builder in linker.builders.values) {
       _library = builder.element;
       for (var unit in _library.units) {
+        _unitElement = unit;
         unit.extensions.forEach(_resolveExtensionFields);
         unit.mixins.forEach(_resolveClassFields);
         unit.types.forEach(_resolveClassFields);
@@ -90,14 +91,14 @@
     if (typeNode != null) {
       if (declarationList.isConst ||
           declarationList.isFinal && _enclosingClassHasConstConstructor) {
-        var holder = ElementHolder();
-        variable.initializer.accept(LocalElementBuilder(holder, null));
-        (element as VariableElementImpl).encloseElements(holder.functions);
-
-        var astResolver = AstResolver(linker, _library, _scope);
-        astResolver.rewriteAst(variable.initializer);
-        InferenceContext.setType(variable.initializer, typeNode.type);
-        astResolver.resolve(variable.initializer);
+        var astResolver = AstResolver(linker, _unitElement, _scope);
+        astResolver.resolve(
+          variable.initializer,
+          () {
+            InferenceContext.setType(variable.initializer, typeNode.type);
+            return variable.initializer;
+          },
+        );
       }
     }
   }
@@ -292,15 +293,15 @@
   final Linker _linker;
   final _InferenceWalker _walker;
 
-  LibraryElement _library;
+  CompilationUnitElement _unitElement;
   Scope _scope;
 
   _InitializerInference(this._linker) : _walker = _InferenceWalker(_linker);
 
   void createNodes() {
     for (var builder in _linker.builders.values) {
-      _library = builder.element;
-      for (var unit in _library.units) {
+      for (var unit in builder.element.units) {
+        _unitElement = unit;
         unit.extensions.forEach(_addExtensionElementFields);
         unit.mixins.forEach(_addClassElementFields);
         unit.types.forEach(_addClassConstructorFieldFormals);
@@ -357,7 +358,7 @@
 
     if (node.initializer != null) {
       var inferenceNode =
-          _VariableInferenceNode(_walker, _library, _scope, element, node);
+          _VariableInferenceNode(_walker, _unitElement, _scope, node);
       _walker._nodes[element] = inferenceNode;
       (element as PropertyInducingElementImpl).initializer =
           _FunctionElementForLink_Initializer(inferenceNode);
@@ -369,9 +370,8 @@
 
 class _VariableInferenceNode extends _InferenceNode {
   final _InferenceWalker _walker;
-  final LibraryElement _library;
+  final CompilationUnitElement _unitElement;
   final Scope _scope;
-  final PropertyInducingElementImpl _element;
   final VariableDeclaration _node;
 
   @override
@@ -379,9 +379,8 @@
 
   _VariableInferenceNode(
     this._walker,
-    this._library,
+    this._unitElement,
     this._scope,
-    this._element,
     this._node,
   );
 
@@ -401,7 +400,6 @@
 
   @override
   List<_InferenceNode> computeDependencies() {
-    _buildLocalElements();
     _resolveInitializer();
 
     var collector = _InferenceDependenciesCollector();
@@ -461,15 +459,8 @@
     isEvaluated = true;
   }
 
-  void _buildLocalElements() {
-    var holder = ElementHolder();
-    _node.initializer.accept(LocalElementBuilder(holder, null));
-    _element.encloseElements(holder.functions);
-  }
-
   void _resolveInitializer() {
-    var astResolver = AstResolver(_walker._linker, _library, _scope);
-    astResolver.rewriteAst(_node.initializer);
-    astResolver.resolve(_node.initializer);
+    var astResolver = AstResolver(_walker._linker, _unitElement, _scope);
+    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 f470c13..aa37167 100644
--- a/pkg/analyzer/lib/src/summary2/types_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/types_builder.dart
@@ -55,6 +55,7 @@
     TypeParameterList typeParameterList,
     TypeAnnotation returnTypeNode,
     FormalParameterList parameterList,
+    NullabilitySuffix nullabilitySuffix,
   ) {
     var returnType = returnTypeNode?.type ?? _dynamicType;
 
@@ -80,6 +81,7 @@
       returnType,
       typeParameters,
       formalParameters,
+      nullabilitySuffix: nullabilitySuffix,
     );
   }
 
@@ -149,6 +151,7 @@
         node.typeParameters,
         node.type,
         parameterList,
+        _nullability(node, true), // TODO(scheglov) use 'question' token
       );
       LazyAst.setType(node, type);
     } else {
@@ -166,10 +169,34 @@
       node.typeParameters,
       node.returnType,
       node.parameters,
+      _nullability(node, node.question != null),
     );
     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);
+  }
+
+  NullabilitySuffix _nullability(AstNode node, bool hasQuestion) {
+    if (_nonNullableEnabled(node)) {
+      if (hasQuestion) {
+        return NullabilitySuffix.question;
+      } else {
+        return NullabilitySuffix.none;
+      }
+    } else {
+      return NullabilitySuffix.star;
+    }
+  }
+
   static DartType _getType(FormalParameter node) {
     if (node is DefaultFormalParameter) {
       return _getType(node.parameter);
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index 655444f..15c9568 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -1356,6 +1356,11 @@
   }
 
   void _visitForEachParts(ForEachParts node, SimpleIdentifier loopVariable) {
+    if (loopVariable.staticElement is! VariableElement) {
+      return;
+    }
+    VariableElement loopVariableElement = loopVariable.staticElement;
+
     // Safely handle malformed statements.
     if (loopVariable == null) {
       return;
@@ -1396,7 +1401,7 @@
     if (elementType != null) {
       // Insert a cast from the sequence's element type to the loop variable's
       // if needed.
-      _checkImplicitCast(loopVariable, _getExpressionType(loopVariable),
+      _checkImplicitCast(loopVariable, loopVariableElement.type,
           from: elementType);
     }
   }
diff --git a/pkg/analyzer/lib/src/test_utilities/find_element.dart b/pkg/analyzer/lib/src/test_utilities/find_element.dart
index 3632f39..4e5f626 100644
--- a/pkg/analyzer/lib/src/test_utilities/find_element.dart
+++ b/pkg/analyzer/lib/src/test_utilities/find_element.dart
@@ -4,7 +4,6 @@
 
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
-import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/test_utilities/function_ast_visitor.dart';
 
 /// Helper for finding elements declared in the resolved [unit].
@@ -238,10 +237,6 @@
     return ImportFindElement(import);
   }
 
-  InterfaceType interfaceType(String name) {
-    return class_(name).type;
-  }
-
   FunctionElement localFunction(String name) {
     FunctionElement result;
 
@@ -266,15 +261,21 @@
   LocalVariableElement localVar(String name) {
     LocalVariableElement result;
 
-    unit.accept(new FunctionAstVisitor(
-      variableDeclaration: (node) {
-        var element = node.declaredElement;
-        if (element is LocalVariableElement && element.name == name) {
-          if (result != null) {
-            throw StateError('Not unique: $name');
-          }
-          result = element;
+    void updateResult(Element element) {
+      if (element is LocalVariableElement && element.name == name) {
+        if (result != null) {
+          throw StateError('Not unique: $name');
         }
+        result = element;
+      }
+    }
+
+    unit.accept(new FunctionAstVisitor(
+      declaredIdentifier: (node) {
+        updateResult(node.declaredElement);
+      },
+      variableDeclaration: (node) {
+        updateResult(node.declaredElement);
       },
     ));
 
@@ -381,6 +382,13 @@
       }
     }
 
+    unit.accept(
+      FunctionAstVisitor(functionDeclarationStatement: (node) {
+        var functionElement = node.functionDeclaration.declaredElement;
+        findIn(functionElement.parameters);
+      }),
+    );
+
     if (result != null) {
       return result;
     }
diff --git a/pkg/analyzer/lib/src/test_utilities/function_ast_visitor.dart b/pkg/analyzer/lib/src/test_utilities/function_ast_visitor.dart
index df7a2f1..28284ee 100644
--- a/pkg/analyzer/lib/src/test_utilities/function_ast_visitor.dart
+++ b/pkg/analyzer/lib/src/test_utilities/function_ast_visitor.dart
@@ -7,15 +7,26 @@
 
 /// [RecursiveAstVisitor] that delegates visit methods to functions.
 class FunctionAstVisitor extends RecursiveAstVisitor<void> {
+  final void Function(DeclaredIdentifier) declaredIdentifier;
   final void Function(FunctionDeclarationStatement)
       functionDeclarationStatement;
   final void Function(SimpleIdentifier) simpleIdentifier;
   final void Function(VariableDeclaration) variableDeclaration;
 
-  FunctionAstVisitor(
-      {this.functionDeclarationStatement,
-      this.simpleIdentifier,
-      this.variableDeclaration});
+  FunctionAstVisitor({
+    this.declaredIdentifier,
+    this.functionDeclarationStatement,
+    this.simpleIdentifier,
+    this.variableDeclaration,
+  });
+
+  @override
+  void visitDeclaredIdentifier(DeclaredIdentifier node) {
+    if (declaredIdentifier != null) {
+      declaredIdentifier(node);
+    }
+    super.visitDeclaredIdentifier(node);
+  }
 
   @override
   void visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
diff --git a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
index da08116..ff822c1 100644
--- a/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
+++ b/pkg/analyzer/lib/src/test_utilities/mock_sdk.dart
@@ -478,6 +478,66 @@
   ],
 );
 
+final MockSdkLibrary _LIB_FFI = MockSdkLibrary([
+  MockSdkLibraryUnit(
+    'dart:ffi',
+    '$sdkRoot/lib/ffi/ffi.dart',
+    '''
+library dart.ffi;
+class NativeType {
+  const NativeType();
+}
+class Void extends NativeType {}
+class Int8 extends NativeType {
+  const Int8();
+}
+class Uint8 extends NativeType {
+  const Uint8();
+}
+class Int16 extends NativeType {
+  const Int16();
+}
+class Uint16 extends NativeType {
+  const Uint16();
+}
+class Int32 extends NativeType {
+  const Int32();
+}
+class Uint32 extends NativeType {
+  const Uint32();
+}
+class Int64 extends NativeType {
+  const Int64();
+}
+class Uint64 extends NativeType {
+  const Uint64();
+}
+class Float extends NativeType {
+  const Float();
+}
+class Double extends NativeType {
+  const Double();
+}
+class Pointer<T extends NativeType> extends NativeType {
+  static Pointer<NativeFunction<T>> fromFunction<T extends Function>(
+      @DartRepresentationOf("T") Function f,
+      [Object exceptionalReturn]);
+  R asFunction<@DartRepresentationOf("T") R extends Function>();
+}
+class Struct extends NativeType {}
+
+abstract class DynamicLibrary {
+  F lookupFunction<T extends Function, F extends Function>(String symbolName);
+}
+abstract class NativeFunction<T extends Function> extends NativeType {}
+
+class DartRepresentationOf {
+  const DartRepresentationOf(String nativeType);
+}
+''',
+  )
+]);
+
 final MockSdkLibrary _LIB_FOREIGN_HELPER = MockSdkLibrary(
   [
     MockSdkLibraryUnit(
@@ -944,6 +1004,7 @@
   _LIB_ASYNC2,
   _LIB_COLLECTION,
   _LIB_CONVERT,
+  _LIB_FFI,
   _LIB_FOREIGN_HELPER,
   _LIB_IO,
   _LIB_MATH,
@@ -958,6 +1019,7 @@
   'collection': 'const LibraryInfo("collection/collection.dart")',
   'convert': 'const LibraryInfo("convert/convert.dart")',
   'core': 'const LibraryInfo("core/core.dart")',
+  'ffi': 'const LibraryInfo("ffi/ffi.dart")',
   'html': 'const LibraryInfo("html/dartium/html_dartium.dart", '
       'dart2jsPath: "html/dart2js/html_dart2js.dart")',
   'io': 'const LibraryInfo("io/io.dart")',
diff --git a/pkg/analyzer/test/error/error_test.dart b/pkg/analyzer/test/error/error_test.dart
index e07ea71..8ad29bf 100644
--- a/pkg/analyzer/test/error/error_test.dart
+++ b/pkg/analyzer/test/error/error_test.dart
@@ -81,6 +81,7 @@
     List<String> missingCodes = <String>[];
     List<List<String>> declaringPaths = [
       ['lib', 'src', 'analysis_options', 'error', 'option_codes.dart'],
+      ['lib', 'src', 'dart', 'error', 'ffi_code.dart'],
       ['lib', 'src', 'dart', 'error', 'hint_codes.dart'],
       ['lib', 'src', 'dart', 'error', 'lint_codes.dart'],
       ['lib', 'src', 'dart', 'error', 'todo_codes.dart'],
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
index 11a75d9..0bb8690 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -298,6 +298,31 @@
     VariableDeclaration variable = variables[0];
     expect(variable.name, isNotNull);
   }
+
+  void test_parse_member_called_late() {
+    CompilationUnitImpl unit = parseCompilationUnit(
+        'class C { void late() { new C().late(); } }',
+        featureSet: nonNullable);
+    ClassDeclaration declaration = unit.declarations[0];
+    MethodDeclaration method = declaration.members[0];
+
+    expect(method.documentationComment, isNull);
+    expect(method.externalKeyword, isNull);
+    expect(method.modifierKeyword, isNull);
+    expect(method.propertyKeyword, isNull);
+    expect(method.returnType, isNotNull);
+    expect(method.name.name, 'late');
+    expect(method.operatorKeyword, isNull);
+    expect(method.typeParameters, isNull);
+    expect(method.parameters, isNotNull);
+    expect(method.body, isNotNull);
+
+    BlockFunctionBody body = method.body;
+    ExpressionStatement statement = body.block.statements[0];
+    MethodInvocation invocation = statement.expression;
+    expect(invocation.operator.lexeme, '.');
+    expect(invocation.toSource(), 'new C().late()');
+  }
 }
 
 /**
@@ -1615,6 +1640,25 @@
             ));
   }
 
+  void test_parse_toplevel_member_called_late_calling_self() {
+    CompilationUnitImpl unit = parseCompilationUnit('void late() { late(); }',
+        featureSet: nonNullable);
+    FunctionDeclaration method = unit.declarations[0];
+
+    expect(method.documentationComment, isNull);
+    expect(method.externalKeyword, isNull);
+    expect(method.propertyKeyword, isNull);
+    expect(method.returnType, isNotNull);
+    expect(method.name.name, 'late');
+    expect(method.functionExpression, isNotNull);
+
+    BlockFunctionBody body = method.functionExpression.body;
+    ExpressionStatement statement = body.block.statements[0];
+    MethodInvocation invocation = statement.expression;
+    expect(invocation.operator, isNull);
+    expect(invocation.toSource(), 'late()');
+  }
+
   void test_complex_extends() {
     var unit = parseCompilationUnit(
         'extension E extends A with B, C implements D { }',
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 13b33eb..e6f891e 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -37,7 +37,6 @@
 
 main() {
   defineReflectiveSuite(() {
-    defineReflectiveTests(ChangeSetTest);
     defineReflectiveTests(EnclosedScopeTest);
     defineReflectiveTests(ErrorResolverTest);
     defineReflectiveTests(LibraryImportScopeTest);
@@ -60,56 +59,6 @@
 }
 
 @reflectiveTest
-class ChangeSetTest {
-  void test_changedContent() {
-    TestSource source = new TestSource();
-    String content = "";
-    ChangeSet changeSet = new ChangeSet();
-    changeSet.changedContent(source, content);
-    expect(changeSet.addedSources, hasLength(0));
-    expect(changeSet.changedSources, hasLength(0));
-    Map<Source, String> map = changeSet.changedContents;
-    expect(map, hasLength(1));
-    expect(map[source], same(content));
-    expect(changeSet.changedRanges, hasLength(0));
-    expect(changeSet.removedSources, hasLength(0));
-    expect(changeSet.removedContainers, hasLength(0));
-  }
-
-  void test_changedRange() {
-    TestSource source = new TestSource();
-    String content = "";
-    ChangeSet changeSet = new ChangeSet();
-    changeSet.changedRange(source, content, 1, 2, 3);
-    expect(changeSet.addedSources, hasLength(0));
-    expect(changeSet.changedSources, hasLength(0));
-    expect(changeSet.changedContents, hasLength(0));
-    Map<Source, ChangeSet_ContentChange> map = changeSet.changedRanges;
-    expect(map, hasLength(1));
-    ChangeSet_ContentChange change = map[source];
-    expect(change, isNotNull);
-    expect(change.contents, content);
-    expect(change.offset, 1);
-    expect(change.oldLength, 2);
-    expect(change.newLength, 3);
-    expect(changeSet.removedSources, hasLength(0));
-    expect(changeSet.removedContainers, hasLength(0));
-  }
-
-  void test_toString() {
-    ChangeSet changeSet = new ChangeSet();
-    changeSet.addedSource(new TestSource());
-    changeSet.changedSource(new TestSource());
-    changeSet.changedContent(new TestSource(), "");
-    changeSet.changedRange(new TestSource(), "", 0, 0, 0);
-    changeSet.removedSource(new TestSource());
-    changeSet
-        .removedContainer(new SourceContainer_ChangeSetTest_test_toString());
-    expect(changeSet.toString(), isNotNull);
-  }
-}
-
-@reflectiveTest
 class EnclosedScopeTest extends DriverResolutionTest {
   test_define_duplicate() async {
     Scope rootScope = new _RootScope();
diff --git a/pkg/analyzer/test/generated/simple_resolver_test.dart b/pkg/analyzer/test/generated/simple_resolver_test.dart
index 7df3a66..9a2e72b 100644
--- a/pkg/analyzer/test/generated/simple_resolver_test.dart
+++ b/pkg/analyzer/test/generated/simple_resolver_test.dart
@@ -573,11 +573,7 @@
     );
   }
 
-  @failingTest
   test_getter_and_setter_fromMixins_property_access() async {
-    // TODO(paulberry): it appears that auxiliaryElements isn't properly set on
-    // a SimpleIdentifier that's inside a property access.  This bug should be
-    // fixed.
     await resolveTestCode(r'''
 class B {}
 class M1 {
@@ -774,7 +770,6 @@
 }
 ''');
     assertTestErrorsWithCodes([CompileTimeErrorCode.URI_DOES_NOT_EXIST]);
-    verifyTestResolved();
   }
 
   @failingTest
diff --git a/pkg/analyzer/test/generated/static_type_analyzer_test.dart b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
index abfd5fc..d823202 100644
--- a/pkg/analyzer/test/generated/static_type_analyzer_test.dart
+++ b/pkg/analyzer/test/generated/static_type_analyzer_test.dart
@@ -8,7 +8,6 @@
 import 'package:analyzer/dart/ast/ast.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';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/element/element.dart';
@@ -142,7 +141,7 @@
   print(C.m);
 }
 ''');
-    expectFunctionType('m);', 'void Function()');
+    assertType(findNode.simple('m);'), 'void Function()');
   }
 
   test_staticMethods_classTypeParameters_genericMethod() async {
@@ -157,39 +156,14 @@
   print(C.m);
 }
 ''');
-    // C - m
-    TypeParameterType typeS;
-    {
-      FunctionTypeImpl type = expectFunctionType('m);', 'void Function<S>(S)',
-          elementTypeParams: '[S]',
-          typeFormals: '[S]',
-          identifierType: 'void Function<S>(S)');
-
-      typeS = type.typeFormals[0].instantiate(
-        nullabilitySuffix: NullabilitySuffix.star,
-      );
-      type = type.instantiate([DynamicTypeImpl.instance]);
-      expect(type.toString(), 'void Function(dynamic)');
-      expect(type.typeParameters.toString(), '[S]');
-      expect(type.typeArguments, [DynamicTypeImpl.instance]);
-      expect(type.typeFormals, isEmpty);
-    }
-    // C - m - f
-    {
-      FunctionTypeImpl type = expectFunctionType(
-          'f);', 'void Function<U>(S, U)',
-          elementTypeParams: '[U]',
-          typeParams: '[S]',
-          typeArgs: '[S]',
-          typeFormals: '[U]',
-          identifierType: 'void Function<U>(S, U)');
-
-      type = type.instantiate([DynamicTypeImpl.instance]);
-      expect(type.toString(), 'void Function(S, dynamic)');
-      expect(type.typeParameters.toString(), '[S, U]');
-      expect(type.typeArguments, [typeS, DynamicTypeImpl.instance]);
-      expect(type.typeFormals, isEmpty);
-    }
+    assertType(
+      findNode.simple('f);'),
+      'void Function<U>(S, U)',
+    );
+    assertType(
+      findNode.simple('m);'),
+      'void Function<S>(S)',
+    );
   }
 }
 
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
index 7f1e8fe..29f2ccc 100644
--- a/pkg/analyzer/test/generated/strong_mode_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -4304,16 +4304,21 @@
   C<String> cOfString;
 }
 ''');
-    expectFunctionType('f<T>', 'List<T> Function<T>(E)',
-        elementTypeParams: '[T]',
-        typeParams: '[E]',
-        typeArgs: '[E]',
-        typeFormals: '[T]');
-    SimpleIdentifier c = findNode.simple('cOfString');
-    FunctionType ft = (c.staticType as InterfaceType).getMethod('f').type;
-    expect(ft.toString(), 'List<T> Function<T>(String)');
-    ft = ft.instantiate([typeProvider.intType]);
-    expect(ft.toString(), 'List<int> Function(String)');
+    assertElementTypeString(
+      findElement.method('f').type,
+      'List<T> Function<T>(E)',
+    );
+
+    var cOfString = findElement.localVar('cOfString');
+    var ft = (cOfString.type as InterfaceType).getMethod('f').type;
+    assertElementTypeString(
+      ft,
+      'List<T> Function<T>(String)',
+    );
+    assertElementTypeString(
+      ft.instantiate([typeProvider.intType]),
+      'List<int> Function(String)',
+    );
   }
 
   test_genericMethod_explicitTypeParams() async {
@@ -4330,8 +4335,8 @@
     FunctionType ft = f.staticInvokeType;
     expect(ft.toString(), 'List<int> Function(String)');
 
-    SimpleIdentifier x = findNode.simple('x');
-    expect(x.staticType, typeProvider.listType2(typeProvider.intType));
+    var x = findElement.localVar('x');
+    expect(x.type, typeProvider.listType2(typeProvider.intType));
   }
 
   test_genericMethod_functionExpressionInvocation_explicit() async {
@@ -4358,14 +4363,14 @@
   var paramCall = (pf)<int>(3);
 }
 ''');
-    expectIdentifierType('methodCall', "int");
-    expectIdentifierType('staticCall', "int");
-    expectIdentifierType('staticFieldCall', "int");
-    expectIdentifierType('topFunCall', "int");
-    expectIdentifierType('topFieldCall', "int");
-    expectIdentifierType('localCall', "int");
-    expectIdentifierType('paramCall', "int");
-    expectIdentifierType('lambdaCall', "int");
+    _assertLocalVarType('lambdaCall', "int");
+    _assertLocalVarType('methodCall', "int");
+    _assertLocalVarType('staticCall', "int");
+    _assertLocalVarType('staticFieldCall', "int");
+    _assertLocalVarType('topFunCall', "int");
+    _assertLocalVarType('topFieldCall', "int");
+    _assertLocalVarType('localCall', "int");
+    _assertLocalVarType('paramCall', "int");
   }
 
   test_genericMethod_functionExpressionInvocation_functionTypedParameter_explicit() async {
@@ -4374,7 +4379,7 @@
   var paramCall = (pf)<int>(3);
 }
 ''');
-    expectIdentifierType('paramCall', "int");
+    _assertLocalVarType('paramCall', "int");
   }
 
   test_genericMethod_functionExpressionInvocation_functionTypedParameter_inferred() async {
@@ -4383,7 +4388,7 @@
   var paramCall = (pf)(3);
 }
 ''');
-    expectIdentifierType('paramCall', "int");
+    _assertLocalVarType('paramCall', "int");
   }
 
   test_genericMethod_functionExpressionInvocation_inferred() async {
@@ -4410,14 +4415,14 @@
   var paramCall = (pf)(3);
 }
 ''');
-    expectIdentifierType('methodCall', "int");
-    expectIdentifierType('staticCall', "int");
-    expectIdentifierType('staticFieldCall', "int");
-    expectIdentifierType('topFunCall', "int");
-    expectIdentifierType('topFieldCall', "int");
-    expectIdentifierType('localCall', "int");
-    expectIdentifierType('paramCall', "int");
-    expectIdentifierType('lambdaCall', "int");
+    _assertLocalVarType('lambdaCall', "int");
+    _assertLocalVarType('methodCall', "int");
+    _assertLocalVarType('staticCall', "int");
+    _assertLocalVarType('staticFieldCall', "int");
+    _assertLocalVarType('topFunCall', "int");
+    _assertLocalVarType('topFieldCall', "int");
+    _assertLocalVarType('localCall', "int");
+    _assertLocalVarType('paramCall', "int");
   }
 
   test_genericMethod_functionInvocation_explicit() async {
@@ -4442,13 +4447,13 @@
   var paramCall = pf<int>(3);
 }
 ''');
-    expectIdentifierType('methodCall', "int");
-    expectIdentifierType('staticCall', "int");
-    expectIdentifierType('staticFieldCall', "int");
-    expectIdentifierType('topFunCall', "int");
-    expectIdentifierType('topFieldCall', "int");
-    expectIdentifierType('localCall', "int");
-    expectIdentifierType('paramCall', "int");
+    _assertLocalVarType('methodCall', "int");
+    _assertLocalVarType('staticCall', "int");
+    _assertLocalVarType('staticFieldCall', "int");
+    _assertLocalVarType('topFunCall', "int");
+    _assertLocalVarType('topFieldCall', "int");
+    _assertLocalVarType('localCall', "int");
+    _assertLocalVarType('paramCall', "int");
   }
 
   test_genericMethod_functionInvocation_functionTypedParameter_explicit() async {
@@ -4457,7 +4462,7 @@
   var paramCall = pf<int>(3);
 }
 ''');
-    expectIdentifierType('paramCall', "int");
+    _assertLocalVarType('paramCall', "int");
   }
 
   test_genericMethod_functionInvocation_functionTypedParameter_inferred() async {
@@ -4466,7 +4471,7 @@
   var paramCall = pf(3);
 }
 ''');
-    expectIdentifierType('paramCall', "int");
+    _assertLocalVarType('paramCall', "int");
   }
 
   test_genericMethod_functionInvocation_inferred() async {
@@ -4491,13 +4496,13 @@
   var paramCall = pf(3);
 }
 ''');
-    expectIdentifierType('methodCall', "int");
-    expectIdentifierType('staticCall', "int");
-    expectIdentifierType('staticFieldCall', "int");
-    expectIdentifierType('topFunCall', "int");
-    expectIdentifierType('topFieldCall', "int");
-    expectIdentifierType('localCall', "int");
-    expectIdentifierType('paramCall', "int");
+    _assertLocalVarType('methodCall', "int");
+    _assertLocalVarType('staticCall', "int");
+    _assertLocalVarType('staticFieldCall', "int");
+    _assertLocalVarType('topFunCall', "int");
+    _assertLocalVarType('topFieldCall', "int");
+    _assertLocalVarType('localCall', "int");
+    _assertLocalVarType('paramCall', "int");
   }
 
   test_genericMethod_functionTypedParameter() async {
@@ -4509,17 +4514,21 @@
   C<String> cOfString;
 }
 ''');
-    expectFunctionType('f<T>', 'List<T> Function<T>(T Function(E))',
-        elementTypeParams: '[T]',
-        typeParams: '[E]',
-        typeArgs: '[E]',
-        typeFormals: '[T]');
+    assertElementTypeString(
+      findElement.method('f').type,
+      'List<T> Function<T>(T Function(E))',
+    );
 
-    SimpleIdentifier c = findNode.simple('cOfString');
-    FunctionType ft = (c.staticType as InterfaceType).getMethod('f').type;
-    expect(ft.toString(), 'List<T> Function<T>(T Function(String))');
-    ft = ft.instantiate([typeProvider.intType]);
-    expect(ft.toString(), 'List<int> Function(int Function(String))');
+    var cOfString = findElement.localVar('cOfString');
+    var ft = (cOfString.type as InterfaceType).getMethod('f').type;
+    assertElementTypeString(
+      ft,
+      'List<T> Function<T>(T Function(String))',
+    );
+    assertElementTypeString(
+      ft.instantiate([typeProvider.intType]),
+      'List<int> Function(int Function(String))',
+    );
   }
 
   test_genericMethod_functionTypedParameter_tearoff() async {
@@ -4528,7 +4537,7 @@
   var paramTearOff = pf;
 }
 ''');
-    expectIdentifierType('paramTearOff', "T Function<T>(T)");
+    _assertLocalVarType('paramTearOff', "T Function<T>(T)");
   }
 
   test_genericMethod_implicitDynamic() async {
@@ -4661,8 +4670,14 @@
   return null;
 }
 ''');
-    expectIdentifierType('f<S>', 'S Function<S>(S)');
-    expectIdentifierType('g<S>', 'S Function<S>(S) Function<S>(S)');
+    assertElementTypeString(
+      findElement.topFunction('f').type,
+      'S Function<S>(S)',
+    );
+    assertElementTypeString(
+      findElement.localFunction('g').type,
+      'S Function<S>(S) Function<S>(S)',
+    );
   }
 
   test_genericMethod_override() async {
@@ -4800,7 +4815,7 @@
   }
   return null;
 }''');
-    expectIdentifierType('y = ', 'List<C>');
+    _assertLocalVarType('y', 'List<C>');
   }
 
   test_genericMethod_tearoff() async {
@@ -4825,13 +4840,13 @@
   var paramTearOff = pf;
 }
 ''');
-    expectIdentifierType('methodTearOff', "T Function<T>(int)");
-    expectIdentifierType('staticTearOff', "T Function<T>(T)");
-    expectIdentifierType('staticFieldTearOff', "T Function<T>(T)");
-    expectIdentifierType('topFunTearOff', "T Function<T>(T)");
-    expectIdentifierType('topFieldTearOff', "T Function<T>(T)");
-    expectIdentifierType('localTearOff', "T Function<T>(T)");
-    expectIdentifierType('paramTearOff', "T Function<T>(T)");
+    _assertLocalVarType('methodTearOff', "T Function<T>(int)");
+    _assertLocalVarType('staticTearOff', "T Function<T>(T)");
+    _assertLocalVarType('staticFieldTearOff', "T Function<T>(T)");
+    _assertLocalVarType('topFunTearOff', "T Function<T>(T)");
+    _assertLocalVarType('topFieldTearOff', "T Function<T>(T)");
+    _assertLocalVarType('localTearOff', "T Function<T>(T)");
+    _assertLocalVarType('paramTearOff', "T Function<T>(T)");
   }
 
   @failingTest
@@ -4921,7 +4936,7 @@
   var fieldRead = C.h;
 }
 ''');
-    expectIdentifierType('fieldRead', "T Function<T>(T)");
+    _assertLocalVarType('fieldRead', "T Function<T>(T)");
   }
 
   test_implicitBounds() async {
@@ -4933,7 +4948,6 @@
 class C<S extends int, T extends B<S>, U extends A> {}
 
 void test() {
-//
   A ai;
   B bi;
   C ci;
@@ -4942,12 +4956,12 @@
   var cc = new C();
 }
 ''');
-    expectIdentifierType('ai', "A<dynamic>");
-    expectIdentifierType('bi', "B<num>");
-    expectIdentifierType('ci', "C<int, B<int>, A<dynamic>>");
-    expectIdentifierType('aa', "A<dynamic>");
-    expectIdentifierType('bb', "B<num>");
-    expectIdentifierType('cc', "C<int, B<int>, A<dynamic>>");
+    _assertLocalVarType('ai', "A<dynamic>");
+    _assertLocalVarType('bi', "B<num>");
+    _assertLocalVarType('ci', "C<int, B<int>, A<dynamic>>");
+    _assertLocalVarType('aa', "A<dynamic>");
+    _assertLocalVarType('bb', "B<num>");
+    _assertLocalVarType('cc', "C<int, B<int>, A<dynamic>>");
   }
 
   test_instantiateToBounds_class_error_extension_malbounded() async {
@@ -4974,7 +4988,7 @@
       error(CompileTimeErrorCode.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS, 81, 1),
       error(StrongModeCode.COULD_NOT_INFER, 81, 1),
     ]);
-    expectIdentifierType('c =', 'C<List<dynamic>, List<List<dynamic>>>');
+    _assertLocalVarType('c', 'C<List<dynamic>, List<List<dynamic>>>');
   }
 
   test_instantiateToBounds_class_error_recursion() async {
@@ -4982,8 +4996,7 @@
 class C<T0 extends List<T1>, T1 extends List<T0>> {}
 C c;
 ''', []);
-
-    expectIdentifierType('c;', 'C<List<dynamic>, List<dynamic>>');
+    _assertTopVarType('c', 'C<List<dynamic>, List<dynamic>>');
   }
 
   test_instantiateToBounds_class_error_recursion_self() async {
@@ -4991,8 +5004,7 @@
 class C<T extends C<T>> {}
 C c;
 ''', []);
-
-    expectIdentifierType('c;', 'C<C<dynamic>>');
+    _assertTopVarType('c', 'C<C<dynamic>>');
   }
 
   test_instantiateToBounds_class_error_recursion_self2() async {
@@ -5001,8 +5013,7 @@
 class C<T extends A<T>> {}
 C c;
 ''', []);
-
-    expectIdentifierType('c;', 'C<A<dynamic>>');
+    _assertTopVarType('c', 'C<A<dynamic>>');
   }
 
   test_instantiateToBounds_class_error_typedef() async {
@@ -5011,8 +5022,7 @@
 class C<T extends F<T>> {}
 C c;
 ''', []);
-
-    expectIdentifierType('c;', 'C<dynamic Function(dynamic)>');
+    _assertTopVarType('c', 'C<dynamic Function(dynamic)>');
   }
 
   test_instantiateToBounds_class_ok_implicitDynamic_multi() async {
@@ -5020,9 +5030,7 @@
 class C<T0 extends Map<T1, T2>, T1 extends List, T2 extends int> {}
 C c;
 ''');
-
-    expectIdentifierType(
-        'c;', 'C<Map<List<dynamic>, int>, List<dynamic>, int>');
+    _assertTopVarType('c', 'C<Map<List<dynamic>, int>, List<dynamic>, int>');
   }
 
   test_instantiateToBounds_class_ok_referenceOther_after() async {
@@ -5030,8 +5038,7 @@
 class C<T0 extends T1, T1 extends int> {}
 C c;
 ''');
-
-    expectIdentifierType('c;', 'C<int, int>');
+    _assertTopVarType('c', 'C<int, int>');
   }
 
   test_instantiateToBounds_class_ok_referenceOther_after2() async {
@@ -5039,8 +5046,7 @@
 class C<T0 extends Map<T1, T1>, T1 extends int> {}
 C c;
 ''');
-
-    expectIdentifierType('c;', 'C<Map<int, int>, int>');
+    _assertTopVarType('c', 'C<Map<int, int>, int>');
   }
 
   test_instantiateToBounds_class_ok_referenceOther_before() async {
@@ -5048,8 +5054,7 @@
 class C<T0 extends int, T1 extends T0> {}
 C c;
 ''');
-
-    expectIdentifierType('c;', 'C<int, int>');
+    _assertTopVarType('c', 'C<int, int>');
   }
 
   test_instantiateToBounds_class_ok_referenceOther_multi() async {
@@ -5057,8 +5062,7 @@
 class C<T0 extends Map<T1, T2>, T1 extends List<T2>, T2 extends int> {}
 C c;
 ''');
-
-    expectIdentifierType('c;', 'C<Map<List<int>, int>, List<int>, int>');
+    _assertTopVarType('c', 'C<Map<List<int>, int>, List<int>, int>');
   }
 
   test_instantiateToBounds_class_ok_simpleBounds() async {
@@ -5074,11 +5078,10 @@
   D d;
 }
 ''');
-
-    expectIdentifierType('a;', 'A<dynamic>');
-    expectIdentifierType('b;', 'B<num>');
-    expectIdentifierType('c;', 'C<List<int>>');
-    expectIdentifierType('d;', 'D<A<dynamic>>');
+    _assertLocalVarType('a', 'A<dynamic>');
+    _assertLocalVarType('b', 'B<num>');
+    _assertLocalVarType('c', 'C<List<int>>');
+    _assertLocalVarType('d', 'D<A<dynamic>>');
   }
 
   test_instantiateToBounds_generic_function_error_malbounded() async {
@@ -5095,7 +5098,7 @@
       error(HintCode.UNUSED_LOCAL_VARIABLE, 69, 1),
       error(StrongModeCode.COULD_NOT_INFER, 73, 1),
     ]);
-    expectIdentifierType('c =', 'List<dynamic>');
+    _assertLocalVarType('c', 'List<dynamic>');
   }
 
   test_instantiateToBounds_method_ok_referenceOther_before() async {
@@ -5513,14 +5516,24 @@
     expectInitializerType('foo', 'int');
   }
 
+  void _assertLocalVarType(String name, String expectedType) {
+    var element = findElement.localVar(name);
+    assertElementTypeString(element.type, expectedType);
+  }
+
+  void _assertTopVarType(String name, String expectedType) {
+    var element = findElement.topVar(name);
+    assertElementTypeString(element.type, expectedType);
+  }
+
   Future<void> _objectMethodOnFunctions_helper2(String code) async {
     await assertNoErrorsInCode(code);
-    expectIdentifierType('t0', "String");
-    expectIdentifierType('t1', "String Function()");
-    expectIdentifierType('t2', "int");
-    expectIdentifierType('t3', "String");
-    expectIdentifierType('t4', "String Function()");
-    expectIdentifierType('t5', "int");
+    _assertLocalVarType('t0', "String");
+    _assertLocalVarType('t1', "String Function()");
+    _assertLocalVarType('t2', "int");
+    _assertLocalVarType('t3', "String");
+    _assertLocalVarType('t4', "String Function()");
+    _assertLocalVarType('t5', "int");
   }
 }
 
@@ -5534,7 +5547,7 @@
     v; // marker
   }
 }''');
-    assertTypeDynamic(findNode.simple('v in'));
+    assertElementTypeDynamic(findElement.localVar('v').type);
     assertTypeDynamic(findNode.simple('v; // marker'));
   }
 
@@ -5559,7 +5572,7 @@
     v; // marker
   }
 }''');
-    assertType(findNode.simple('v in'), 'int');
+    assertElementTypeString(findElement.localVar('v').type, 'int');
     assertType(findNode.simple('v; // marker'), 'int');
   }
 
@@ -5571,7 +5584,7 @@
     v; // marker
   }
 }''');
-    assertType(findNode.simple('v in'), 'int');
+    assertElementTypeString(findElement.localVar('v').type, 'int');
     assertType(findNode.simple('v; // marker'), 'int');
   }
 
@@ -5584,7 +5597,7 @@
     v; // marker
   }
 }''');
-    assertType(findNode.simple('v in'), 'int');
+    assertElementTypeString(findElement.localVar('v').type, 'int');
     assertType(findNode.simple('v; // marker'), 'int');
   }
 
@@ -5613,7 +5626,7 @@
   var v = null;
   v; // marker
 }''');
-    assertTypeDynamic(findNode.simple('v ='));
+    assertElementTypeDynamic(findElement.localVar('v').type);
     assertTypeDynamic(findNode.simple('v; // marker'));
   }
 
@@ -5623,7 +5636,7 @@
   var v = 3;
   v; // marker
 }''');
-    assertType(findNode.simple('v ='), 'int');
+    assertElementTypeString(findElement.localVar('v').type, 'int');
     assertType(findNode.simple('v; // marker'), 'int');
   }
 
@@ -5633,7 +5646,7 @@
   dynamic v = 3;
   v; // marker
 }''');
-    assertTypeDynamic(findNode.simple('v ='));
+    assertElementTypeDynamic(findElement.localVar('v').type);
     assertTypeDynamic(findNode.simple('v; // marker'));
   }
 
@@ -5660,7 +5673,7 @@
 main() {
 }
 ''');
-    assertType(findNode.simple('v ='), 'int');
+    assertElementTypeString(findElement.localVar('v').type, 'int');
     assertType(findNode.simple('v; // marker'), 'int');
   }
 
@@ -5676,7 +5689,7 @@
 main() {
 }
 ''');
-    assertType(findNode.simple('v ='), 'int');
+    assertElementTypeString(findElement.localVar('v').type, 'int');
     assertType(findNode.simple('v; // marker'), 'int');
   }
 
@@ -5692,7 +5705,7 @@
 main() {
 }
 ''');
-    assertType(findNode.simple('v ='), 'int');
+    assertElementTypeString(findElement.localVar('v').type, 'int');
     assertType(findNode.simple('v; // marker'), 'int');
   }
 
@@ -5708,7 +5721,7 @@
 main() {
 }
 ''');
-    assertType(findNode.simple('v ='), 'int');
+    assertElementTypeString(findElement.localVar('v').type, 'int');
     assertType(findNode.simple('v; // marker'), 'int');
   }
 
@@ -5719,7 +5732,7 @@
   var v = x[0];
   v; // marker
 }''');
-    assertType(findNode.simple('v ='), 'int');
+    assertElementTypeString(findElement.localVar('v').type, 'int');
     assertType(findNode.simple('v; // marker'), 'int');
   }
 
@@ -5730,7 +5743,7 @@
   var v = x;
   v; // marker
 }''');
-    assertType(findNode.simple('v ='), 'int');
+    assertElementTypeString(findElement.localVar('v').type, 'int');
     assertType(findNode.simple('v; // marker'), 'int');
   }
 
@@ -5742,7 +5755,7 @@
   v; // marker
 }
 ''');
-    assertType(findNode.simple('v ='), 'int');
+    assertElementTypeString(findElement.localVar('v').type, 'int');
     assertType(findNode.simple('v; // marker'), 'int');
   }
 
@@ -5754,7 +5767,7 @@
 }
 final x = 3;
 ''');
-    assertType(findNode.simple('v ='), 'int');
+    assertElementTypeString(findElement.localVar('v').type, 'int');
     assertType(findNode.simple('v; // marker'), 'int');
   }
 
@@ -5766,7 +5779,7 @@
   v; // marker
 }
 ''');
-    assertType(findNode.simple('v ='), 'int');
+    assertElementTypeString(findElement.localVar('v').type, 'int');
     assertType(findNode.simple('v; // marker'), 'int');
   }
 
@@ -5778,7 +5791,7 @@
 }
 int x = 3;
 ''');
-    assertType(findNode.simple('v ='), 'int');
+    assertElementTypeString(findElement.localVar('v').type, 'int');
     assertType(findNode.simple('v; // marker'), 'int');
   }
 }
diff --git a/pkg/analyzer/test/id_tests/nullability_test.dart b/pkg/analyzer/test/id_tests/nullability_test.dart
index 891d5aa..b59081c 100644
--- a/pkg/analyzer/test/id_tests/nullability_test.dart
+++ b/pkg/analyzer/test/id_tests/nullability_test.dart
@@ -70,7 +70,9 @@
 
   @override
   String computeNodeValue(Id id, AstNode node) {
-    if (node is SimpleIdentifier && node.inGetterContext()) {
+    if (node is SimpleIdentifier &&
+        node.inGetterContext() &&
+        !node.inDeclarationContext()) {
       var element = node.staticElement;
       if (element is LocalVariableElement || element is ParameterElement) {
         TypeImpl promotedType = node.staticType;
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 79b0843..f1b3cfc 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
@@ -1111,7 +1111,8 @@
       itemElement1 = itemElement;
 
       expect(closureElement.returnType, typeProvider.nullType);
-      expect(closureElement.type.element, same(closureElement));
+      // TODO(scheglov) Make this null.
+//      expect(closureElement.type.element, same(closureElement));
       expect(closureElement.type.toString(), closureTypeStr);
       expect(closure.staticType, same(closureElement.type));
 
@@ -7401,7 +7402,9 @@
 
       // getter name
       expect(node.name.staticElement, same(node.declaredElement));
-      expect(node.name.staticType, intType);
+      // TODO(scheglov) must be null
+//      assertTypeNull(node.name);
+//      expect(node.name.staticType, intType);
     }
 
     // topSetter()
@@ -7419,7 +7422,9 @@
 
       // setter name
       expect(node.name.staticElement, same(node.declaredElement));
-      expect(node.name.staticType, doubleType);
+      // TODO(scheglov) must be null
+//      assertTypeNull(node.name);
+//      expect(node.name.staticType, doubleType);
 
       // setter parameter
       {
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
index 276fc93..5a6a3f1 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_test.dart
@@ -1373,7 +1373,7 @@
     expect(result.errors, hasLength(0));
 
     var f = result.unit.declarations[0] as FunctionDeclaration;
-    expect(f.name.staticType.toString(), 'int Function()');
+    expect(f.declaredElement.type.toString(), 'int Function()');
     expect(f.returnType.type.toString(), 'int');
 
     // The same result is also received through the stream.
@@ -2909,7 +2909,7 @@
     expect(result.errors, hasLength(0));
 
     var f = result.unit.declarations[0] as FunctionDeclaration;
-    expect(f.name.staticType.toString(), 'int Function()');
+    expect(f.declaredElement.type.toString(), 'int Function()');
     expect(f.returnType.type.toString(), 'int');
   }
 
diff --git a/pkg/analyzer/test/src/dart/element/element_test.dart b/pkg/analyzer/test/src/dart/element/element_test.dart
index d6e9dc2..3db01ca 100644
--- a/pkg/analyzer/test/src/dart/element/element_test.dart
+++ b/pkg/analyzer/test/src/dart/element/element_test.dart
@@ -8,7 +8,6 @@
 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/handle.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
 import 'package:analyzer/src/generated/resolver.dart';
@@ -35,7 +34,6 @@
     defineReflectiveTests(ElementLocationImplTest);
     defineReflectiveTests(ElementImplTest);
     defineReflectiveTests(LibraryElementImplTest);
-    defineReflectiveTests(PropertyAccessorElementImplTest);
     defineReflectiveTests(TopLevelVariableElementImplTest);
   });
 }
@@ -1167,9 +1165,9 @@
     FunctionElement element = ElementFactory.functionElementWithParameters(
         'f', VoidTypeImpl.instance, [
       ElementFactory.requiredParameter2('a', typeProvider.intType),
-      ElementFactory.requiredParameter('b'),
+      ElementFactory.requiredParameter2('b', typeProvider.dynamicType),
       ElementFactory.namedParameter2('c', typeProvider.stringType),
-      ElementFactory.namedParameter('d')
+      ElementFactory.namedParameter2('d', typeProvider.dynamicType)
     ]);
     FunctionTypeImpl type = element.type;
     Map<String, DartType> types = type.namedParameterTypes;
@@ -1183,7 +1181,7 @@
     FunctionElement element = ElementFactory.functionElementWithParameters(
         'f', VoidTypeImpl.instance, [
       ElementFactory.requiredParameter2('a', typeProvider.intType),
-      ElementFactory.requiredParameter('b'),
+      ElementFactory.requiredParameter2('b', typeProvider.dynamicType),
       ElementFactory.positionalParameter2('c', typeProvider.stringType)
     ]);
     FunctionTypeImpl type = element.type;
@@ -1202,7 +1200,7 @@
     FunctionElement element = ElementFactory.functionElementWithParameters(
         'f', VoidTypeImpl.instance, [
       ElementFactory.positionalParameter2('c', typeProvider.stringType),
-      ElementFactory.positionalParameter('d')
+      ElementFactory.positionalParameter2('d', typeProvider.dynamicType)
     ]);
     FunctionTypeImpl type = element.type;
     List<DartType> types = type.normalParameterTypes;
@@ -1220,7 +1218,7 @@
     FunctionElement element = ElementFactory.functionElementWithParameters(
         'f', VoidTypeImpl.instance, [
       ElementFactory.requiredParameter2('a', typeProvider.intType),
-      ElementFactory.requiredParameter('b'),
+      ElementFactory.requiredParameter2('b', typeProvider.dynamicType),
       ElementFactory.positionalParameter2('c', typeProvider.stringType)
     ]);
     FunctionTypeImpl type = element.type;
@@ -1235,9 +1233,9 @@
     FunctionElement element = ElementFactory.functionElementWithParameters(
         'f', VoidTypeImpl.instance, [
       ElementFactory.requiredParameter2('a', typeProvider.intType),
-      ElementFactory.requiredParameter('b'),
+      ElementFactory.requiredParameter2('b', typeProvider.dynamicType),
       ElementFactory.namedParameter2('c', typeProvider.stringType),
-      ElementFactory.namedParameter('d')
+      ElementFactory.namedParameter2('d', typeProvider.dynamicType)
     ]);
     FunctionTypeImpl type = element.type;
     List<DartType> types = type.optionalParameterTypes;
@@ -1255,9 +1253,9 @@
     FunctionElement element = ElementFactory.functionElementWithParameters(
         'f', VoidTypeImpl.instance, [
       ElementFactory.requiredParameter2('a', typeProvider.intType),
-      ElementFactory.requiredParameter('b'),
+      ElementFactory.requiredParameter2('b', typeProvider.dynamicType),
       ElementFactory.positionalParameter2('c', typeProvider.stringType),
-      ElementFactory.positionalParameter('d')
+      ElementFactory.positionalParameter2('d', typeProvider.dynamicType)
     ]);
     FunctionTypeImpl type = element.type;
     List<DartType> types = type.optionalParameterTypes;
@@ -1703,7 +1701,7 @@
     // user (and hence can't participate in circularities).
     FunctionElementImpl f = ElementFactory.functionElement('f');
     FunctionTypeImpl type = f.type;
-    expect(type.newPrune, isNull);
+    expect(type.newPrune, []);
   }
 
   void test_resolveToBound() {
@@ -1802,7 +1800,7 @@
     );
     expect(
       functionTypeAliasType(f).toString(),
-      'C<dynamic Function()> Function()',
+      'dynamic Function()',
     );
   }
 
@@ -3397,55 +3395,6 @@
 }
 
 @reflectiveTest
-class PropertyAccessorElementImplTest {
-  void test_matchesHandle_getter() {
-    CompilationUnitElementImpl compilationUnitElement =
-        ElementFactory.compilationUnit('foo.dart');
-    ElementFactory.library(null, '')
-      ..definingCompilationUnit = compilationUnitElement;
-    PropertyAccessorElementImpl element =
-        ElementFactory.getterElement('x', true, DynamicTypeImpl.instance);
-    compilationUnitElement.accessors = <PropertyAccessorElement>[element];
-    PropertyAccessorElementHandle handle =
-        new PropertyAccessorElementHandle(null, element.location);
-    expect(element.hashCode, handle.hashCode);
-    // ignore: unrelated_type_equality_checks
-    expect(element == handle, isTrue);
-    // ignore: unrelated_type_equality_checks
-    expect(handle == element, isTrue);
-  }
-
-  void test_matchesHandle_setter() {
-    CompilationUnitElementImpl compilationUnitElement =
-        ElementFactory.compilationUnit('foo.dart');
-    ElementFactory.library(null, '')
-      ..definingCompilationUnit = compilationUnitElement;
-    PropertyAccessorElementImpl element =
-        ElementFactory.setterElement('x', true, DynamicTypeImpl.instance);
-    compilationUnitElement.accessors = <PropertyAccessorElement>[element];
-    PropertyAccessorElementHandle handle =
-        new PropertyAccessorElementHandle(null, element.location);
-    expect(element.hashCode, handle.hashCode);
-    // ignore: unrelated_type_equality_checks
-    expect(element == handle, isTrue);
-    // ignore: unrelated_type_equality_checks
-    expect(handle == element, isTrue);
-  }
-}
-
-class TestElementResynthesizer extends ElementResynthesizer {
-  Map<ElementLocation, Element> locationMap;
-
-  TestElementResynthesizer(AnalysisContext context, this.locationMap)
-      : super(context, null);
-
-  @override
-  Element getElement(ElementLocation location) {
-    return locationMap[location];
-  }
-}
-
-@reflectiveTest
 class TopLevelVariableElementImplTest extends DriverResolutionTest {
   test_computeConstantValue() async {
     newFile('/test/lib/a.dart', content: r'''
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 a27a115..36c3d81 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
@@ -128,6 +128,21 @@
     ]);
   }
 
+  test_missingGenericFunction_imported_withPrefix() async {
+    newFile('/test/lib/a.dart', content: r'''
+typedef F<T> = ;
+''');
+    await assertErrorsInCode(r'''
+import 'a.dart' as p;
+
+void f() {
+  p.F.a;
+}
+''', [
+      error(StaticTypeWarningCode.UNDEFINED_GETTER, 40, 1),
+    ]);
+  }
+
   test_type_element() async {
     await resolveTestCode(r'''
 G<int> g;
diff --git a/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart
index 4a95d53..3533254 100644
--- a/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/index_expression_test.dart
@@ -44,7 +44,7 @@
   test_read_generic() async {
     await assertNoErrorsInCode(r'''
 class A<T> {
-  T operator[](int index) => null;
+  T operator[](int index) => throw 42;
 }
 
 main(A<double> a) {
@@ -101,7 +101,7 @@
   test_readWrite_generic() async {
     await assertNoErrorsInCode(r'''
 class A<T> {
-  T operator[](int index) => null;
+  T operator[](int index) => throw 42;
   void operator[]=(int index, T value) {}
 }
 
diff --git a/pkg/analyzer/test/src/dart/resolution/metadata_test.dart b/pkg/analyzer/test/src/dart/resolution/metadata_test.dart
index c617a00..abf7f9d 100644
--- a/pkg/analyzer/test/src/dart/resolution/metadata_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/metadata_test.dart
@@ -2,9 +2,11 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:analyzer/dart/ast/ast.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
+import '../../summary/resolved_ast_printer.dart';
 import 'driver_resolution.dart';
 
 main() {
@@ -15,6 +17,44 @@
 
 @reflectiveTest
 class MetadataResolutionTest extends DriverResolutionTest {
+  test_onFieldFormal() async {
+    await assertNoErrorsInCode(r'''
+class A {
+  const A(_);
+}
+
+class B {
+  final int f;
+  B({@A( A(0) ) this.f});
+}
+''');
+    _assertResolvedNodeText(findNode.annotation('@A'), r'''
+Annotation
+  arguments: ArgumentList
+    arguments
+      InstanceCreationExpression
+        argumentList: ArgumentList
+          arguments
+            IntegerLiteral
+              literal: 0
+              staticType: int
+        constructorName: ConstructorName
+          type: TypeName
+            name: SimpleIdentifier
+              staticElement: self::@class::A
+              staticType: A
+              token: A
+            type: A
+        staticElement: self::@class::A::@constructor::•
+        staticType: A
+  element: self::@class::A::@constructor::•
+  name: SimpleIdentifier
+    staticElement: self::@class::A
+    staticType: Type
+    token: A
+''');
+  }
+
   test_otherLibrary_constructor_named() async {
     newFile('/test/lib/a.dart', content: r'''
 class A {
@@ -119,4 +159,21 @@
     assertElementTypeString(value.type, 'A<int>');
     expect(value.getField('f').toIntValue(), 42);
   }
+
+  void _assertResolvedNodeText(AstNode node, String expected) {
+    var actual = _resolvedNodeText(node);
+    expect(actual, expected);
+  }
+
+  String _resolvedNodeText(AstNode node) {
+    var buffer = StringBuffer();
+    node.accept(
+      ResolvedAstPrinter(
+        selfUriStr: result.uri.toString(),
+        sink: buffer,
+        indent: '',
+      ),
+    );
+    return buffer.toString();
+  }
 }
diff --git a/pkg/analyzer/test/src/dart/resolution/mixin_test.dart b/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
index b69b39a..8ce09b5 100644
--- a/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/mixin_test.dart
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/src/dart/error/syntactic_errors.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:test/test.dart';
@@ -1077,8 +1078,14 @@
 
     var element = findElement.mixin('M');
     assertElementTypes(element.interfaces, [
-      findElement.interfaceType('A'),
-      findElement.interfaceType('B'),
+      findElement.class_('A').instantiate(
+        typeArguments: const [],
+        nullabilitySuffix: NullabilitySuffix.star,
+      ),
+      findElement.class_('B').instantiate(
+        typeArguments: const [],
+        nullabilitySuffix: NullabilitySuffix.star,
+      ),
     ]);
 
     var aRef = findNode.typeName('A, ');
@@ -1325,8 +1332,14 @@
 
     var element = findElement.mixin('M');
     assertElementTypes(element.superclassConstraints, [
-      findElement.interfaceType('A'),
-      findElement.interfaceType('B'),
+      findElement.class_('A').instantiate(
+        typeArguments: const [],
+        nullabilitySuffix: NullabilitySuffix.star,
+      ),
+      findElement.class_('B').instantiate(
+        typeArguments: const [],
+        nullabilitySuffix: NullabilitySuffix.star,
+      ),
     ]);
 
     var aRef = findNode.typeName('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 62ad0fc..2c38049 100644
--- a/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/non_nullable_test.dart
@@ -260,6 +260,76 @@
     assertType(findNode.postfix('x!'), 'Object');
   }
 
+  @FailingTest(
+    reason: 'The question token is not added to FieldFormalParameter yet',
+  )
+  test_parameter_functionTyped_fieldFormal() async {
+    await assertNoErrorsInCode('''
+class A {
+  var f1;
+  var f2;
+  var f3;
+  A.f1(void this.f1());
+  A.f2(void this.f2()?);
+  A.f3({void this.f3()?});
+}
+''');
+    assertElementTypeString(
+      findElement.parameter('f1').type,
+      'void Function()',
+    );
+    assertElementTypeString(
+      findElement.parameter('f2').type,
+      'void Function()?',
+    );
+    assertElementTypeString(
+      findElement.parameter('f3').type,
+      'void Function()?',
+    );
+  }
+
+  test_parameter_functionTyped() async {
+    await assertNoErrorsInCode('''
+void f1(void p1()) {}
+void f2(void p2()?) {}
+void f3({void p3()?}) {}
+''');
+    assertElementTypeString(
+      findElement.parameter('p1').type,
+      'void Function()',
+    );
+    assertElementTypeString(
+      findElement.parameter('p2').type,
+      'void Function()?',
+    );
+    assertElementTypeString(
+      findElement.parameter('p3').type,
+      'void Function()?',
+    );
+  }
+
+  test_parameter_functionTyped_local() async {
+    await assertNoErrorsInCode('''
+f() {
+  void f1(void p1()) {}
+  void f2(void p2()?) {}
+  void f3({void p3()?}) {}
+}
+''');
+    assertElementTypeString(
+      findElement.parameter('p1').type,
+      'void Function()',
+    );
+    assertElementTypeString(
+      findElement.parameter('p2').type,
+      'void Function()?',
+    );
+    assertElementTypeString(
+      findElement.parameter('p3').type,
+      'void Function()?',
+    );
+  }
+
   @failingTest
   test_parameter_genericFunctionType() async {
     await resolveTestCode('''
diff --git a/pkg/analyzer/test/src/dart/resolution/resolution.dart b/pkg/analyzer/test/src/dart/resolution/resolution.dart
index aa18ac4..9f09f96 100644
--- a/pkg/analyzer/test/src/dart/resolution/resolution.dart
+++ b/pkg/analyzer/test/src/dart/resolution/resolution.dart
@@ -11,7 +11,6 @@
 import 'package:analyzer/error/error.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/handle.dart';
 import 'package:analyzer/src/dart/element/member.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/error/hint_codes.dart';
@@ -120,7 +119,6 @@
 
   void assertElement(AstNode node, Element expected) {
     Element actual = getNodeElement(node);
-    actual = _unwrapHandle(actual);
     expect(actual, same(expected));
   }
 
@@ -523,13 +521,6 @@
   String typeString(DartType type) => (type as TypeImpl)
       ?.toString(withNullability: typeToStringWithNullability);
 
-  Element _unwrapHandle(Element element) {
-    if (element is ElementHandle && element is! Member) {
-      return element.actualElement;
-    }
-    return element;
-  }
-
   static String _extractReturnType(String invokeType) {
     int functionIndex = invokeType.indexOf(' Function');
     expect(functionIndex, isNonNegative);
diff --git a/pkg/analyzer/test/src/diagnostics/annotation_on_pointer_field_test.dart b/pkg/analyzer/test/src/diagnostics/annotation_on_pointer_field_test.dart
new file mode 100644
index 0000000..f67ffd0
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/annotation_on_pointer_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.
+
+import 'package:analyzer/src/dart/error/ffi_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(AnnotationOnPointerFieldTest);
+  });
+}
+
+@reflectiveTest
+class AnnotationOnPointerFieldTest extends DriverResolutionTest {
+  test_double() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Struct {
+  @Double() Pointer<Int8> x;
+}
+''', [
+      error(FfiCode.ANNOTATION_ON_POINTER_FIELD, 46, 9),
+    ]);
+  }
+
+  test_int32() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Struct {
+  @Int32() Pointer<Float> x;
+}
+''', [
+      error(FfiCode.ANNOTATION_ON_POINTER_FIELD, 46, 8),
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/extra_annotation_on_struct_field_test.dart b/pkg/analyzer/test/src/diagnostics/extra_annotation_on_struct_field_test.dart
new file mode 100644
index 0000000..4110fd5
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/extra_annotation_on_struct_field_test.dart
@@ -0,0 +1,37 @@
+// 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/dart/error/ffi_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ExtraAnnotationOnStructFieldTest);
+  });
+}
+
+@reflectiveTest
+class ExtraAnnotationOnStructFieldTest extends DriverResolutionTest {
+  test_one() async {
+    await assertNoErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Struct {
+  @Int32() int x;
+}
+''');
+  }
+
+  test_two() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Struct {
+  @Int32() @Int16() int x;
+}
+''', [
+      error(FfiCode.EXTRA_ANNOTATION_ON_STRUCT_FIELD, 55, 8),
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/field_in_struct_with_initializer_test.dart b/pkg/analyzer/test/src/diagnostics/field_in_struct_with_initializer_test.dart
new file mode 100644
index 0000000..0268520
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/field_in_struct_with_initializer_test.dart
@@ -0,0 +1,46 @@
+// 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/dart/error/ffi_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(FieldInStructWithInitializerTest);
+  });
+}
+
+@reflectiveTest
+class FieldInStructWithInitializerTest extends DriverResolutionTest {
+  test_instance_withInitializer() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Struct {
+  Pointer p = null;
+}
+''', [
+      error(FfiCode.FIELD_IN_STRUCT_WITH_INITIALIZER, 54, 1),
+    ]);
+  }
+
+  test_instance_withoutInitializer() async {
+    await assertNoErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Struct {
+  Pointer p;
+}
+''');
+  }
+
+  test_static_withInitializer() async {
+    await assertNoErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Struct {
+  static String str = '';
+}
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/field_initializer_in_struct_test.dart b/pkg/analyzer/test/src/diagnostics/field_initializer_in_struct_test.dart
new file mode 100644
index 0000000..d0a3c36
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/field_initializer_in_struct_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.
+
+import 'package:analyzer/src/dart/error/ffi_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(FieldInitializerInStructTest);
+  });
+}
+
+@reflectiveTest
+class FieldInitializerInStructTest extends DriverResolutionTest {
+  test_fieldInitializer() async {
+    await assertErrorsInCode('''
+import 'dart:ffi';
+class C extends Struct {
+  @Int32() int f;
+  C() : f = 0;
+}
+''', [
+      error(FfiCode.FIELD_INITIALIZER_IN_STRUCT, 70, 5),
+    ]);
+  }
+
+  test_superInitializer() async {
+    await assertNoErrorsInCode('''
+import 'dart:ffi';
+class C extends Struct {
+  @Int32() int f;
+  C() : super();
+}
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/generic_struct_subclass_test.dart b/pkg/analyzer/test/src/diagnostics/generic_struct_subclass_test.dart
new file mode 100644
index 0000000..ace933d
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/generic_struct_subclass_test.dart
@@ -0,0 +1,33 @@
+// 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/dart/error/ffi_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(GenericStructSubclassTest);
+  });
+}
+
+@reflectiveTest
+class GenericStructSubclassTest extends DriverResolutionTest {
+  test_genericStruct() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class S<T> extends Struct {}
+''', [
+      error(FfiCode.GENERIC_STRUCT_SUBCLASS, 25, 1),
+    ]);
+  }
+
+  test_validStruct() async {
+    await assertNoErrorsInCode(r'''
+import 'dart:ffi';
+class S extends Struct {}
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_exception_value_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_exception_value_test.dart
new file mode 100644
index 0000000..2d3b9b1
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/invalid_exception_value_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.
+
+import 'package:analyzer/src/dart/error/ffi_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(InvalidExceptionValueTest);
+  });
+}
+
+@reflectiveTest
+class InvalidExceptionValueTest extends DriverResolutionTest {
+  test_missing() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+typedef T = Void Function(Int8);
+void f(int i) {}
+void g() {
+  Pointer.fromFunction<T>(f, 42);
+}
+''', [
+      error(FfiCode.INVALID_EXCEPTION_VALUE, 109, 2),
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_field_type_in_struct_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_field_type_in_struct_test.dart
new file mode 100644
index 0000000..7a0e10d
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/invalid_field_type_in_struct_test.dart
@@ -0,0 +1,46 @@
+// 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/dart/error/ffi_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(InvalidFieldTypeInStructTest);
+  });
+}
+
+@reflectiveTest
+class InvalidFieldTypeInStructTest extends DriverResolutionTest {
+  test_instance_invalid() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Struct {
+  String str;
+}
+''', [
+      error(FfiCode.INVALID_FIELD_TYPE_IN_STRUCT, 46, 6),
+    ]);
+  }
+
+  test_instance_valid() async {
+    await assertNoErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Struct {
+  Pointer p;
+}
+''');
+  }
+
+  test_static() async {
+    await assertNoErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Struct {
+  static String str;
+}
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/invalid_use_of_covariant_in_extension_test.dart b/pkg/analyzer/test/src/diagnostics/invalid_use_of_covariant_in_extension_test.dart
index c147375..eef240a 100644
--- a/pkg/analyzer/test/src/diagnostics/invalid_use_of_covariant_in_extension_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/invalid_use_of_covariant_in_extension_test.dart
@@ -3,8 +3,8 @@
 // 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:analyzer/src/generated/parser.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import '../dart/resolution/driver_resolution.dart';
@@ -28,7 +28,7 @@
   void foo({covariant int a}) {}
 }
 ''', [
-      error(CompileTimeErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION, 36, 9),
+      error(ParserErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION, 36, 9),
     ]);
   }
 
@@ -38,7 +38,7 @@
   void foo([covariant int a]) {}
 }
 ''', [
-      error(CompileTimeErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION, 36, 9),
+      error(ParserErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION, 36, 9),
     ]);
   }
 
@@ -48,7 +48,7 @@
   void foo(covariant int a) {}
 }
 ''', [
-      error(CompileTimeErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION, 35, 9),
+      error(ParserErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION, 35, 9),
     ]);
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/mismatched_annotation_on_struct_field_test.dart b/pkg/analyzer/test/src/diagnostics/mismatched_annotation_on_struct_field_test.dart
new file mode 100644
index 0000000..1e5a88a
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/mismatched_annotation_on_struct_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.
+
+import 'package:analyzer/src/dart/error/ffi_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(MismatchedAnnotationOnStructFieldTest);
+  });
+}
+
+@reflectiveTest
+class MismatchedAnnotationOnStructFieldTest extends DriverResolutionTest {
+  test_double_on_int() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Struct {
+  @Double() int x;
+}
+''', [
+      error(FfiCode.MISMATCHED_ANNOTATION_ON_STRUCT_FIELD, 46, 9),
+    ]);
+  }
+
+  test_int32_on_double() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Struct {
+  @Int32() double x;
+}
+''', [
+      error(FfiCode.MISMATCHED_ANNOTATION_ON_STRUCT_FIELD, 46, 8),
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/missing_annotation_on_struct_field_test.dart b/pkg/analyzer/test/src/diagnostics/missing_annotation_on_struct_field_test.dart
new file mode 100644
index 0000000..0e7fdde
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/missing_annotation_on_struct_field_test.dart
@@ -0,0 +1,37 @@
+// 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/dart/error/ffi_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(MissingAnnotationOnStructFieldTest);
+  });
+}
+
+@reflectiveTest
+class MissingAnnotationOnStructFieldTest extends DriverResolutionTest {
+  test_missing_int() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Struct {
+  int x;
+}
+''', [
+      error(FfiCode.MISSING_ANNOTATION_ON_STRUCT_FIELD, 46, 3),
+    ]);
+  }
+
+  test_notMissing() async {
+    await assertNoErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Struct {
+  @Int32() int x;
+}
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/missing_exception_value_test.dart b/pkg/analyzer/test/src/diagnostics/missing_exception_value_test.dart
new file mode 100644
index 0000000..cbc7895
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/missing_exception_value_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.
+
+import 'package:analyzer/src/dart/error/ffi_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(MissingExceptionValueTest);
+  });
+}
+
+@reflectiveTest
+class MissingExceptionValueTest extends DriverResolutionTest {
+  test_missing() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+typedef T = Int8 Function(Int8);
+int f(int i) => i * 2;
+void g() {
+  Pointer.fromFunction<T>(f);
+}
+''', [
+      error(FfiCode.MISSING_EXCEPTION_VALUE, 96, 12),
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/missing_field_type_in_struct_test.dart b/pkg/analyzer/test/src/diagnostics/missing_field_type_in_struct_test.dart
new file mode 100644
index 0000000..2955f38
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/missing_field_type_in_struct_test.dart
@@ -0,0 +1,37 @@
+// 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/dart/error/ffi_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(MissingFieldTypeInStructTest);
+  });
+}
+
+@reflectiveTest
+class MissingFieldTypeInStructTest extends DriverResolutionTest {
+  test_missing() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Struct {
+  var str;
+}
+''', [
+      error(FfiCode.MISSING_FIELD_TYPE_IN_STRUCT, 50, 3),
+    ]);
+  }
+
+  test_valid() async {
+    await assertNoErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Struct {
+  Pointer p;
+}
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/missing_required_param_test.dart b/pkg/analyzer/test/src/diagnostics/missing_required_param_test.dart
index de01ca4..d2bd02d 100644
--- a/pkg/analyzer/test/src/diagnostics/missing_required_param_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/missing_required_param_test.dart
@@ -19,7 +19,7 @@
 
 @reflectiveTest
 class MissingRequiredParamTest extends DriverResolutionTest with PackageMixin {
-  test_constructorParam_argumentGiven() async {
+  test_constructor_argumentGiven() async {
     addMetaPackage();
     await assertNoErrorsInCode(r'''
 import 'package:meta/meta.dart';
@@ -34,7 +34,7 @@
 ''');
   }
 
-  test_constructorParam_missingArgument() async {
+  test_constructor_hasReason() async {
     addMetaPackage();
     await assertErrorsInCode(r'''
 import 'package:meta/meta.dart';
@@ -49,7 +49,7 @@
     ]);
   }
 
-  test_constructorParam_noReason() async {
+  test_constructor_noReason() async {
     addMetaPackage();
     await assertErrorsInCode(r'''
 import 'package:meta/meta.dart';
@@ -66,7 +66,24 @@
     ]);
   }
 
-  test_constructorParam_nullReason() async {
+  test_constructor_noReason_generic() async {
+    addMetaPackage();
+    await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+class C<T> {
+  C({@required int a}) {}
+}
+
+main() {
+  new C();
+}
+''', [
+      error(HintCode.MISSING_REQUIRED_PARAM, 91, 1),
+    ]);
+  }
+
+  test_constructor_nullReason() async {
     addMetaPackage();
     await assertErrorsInCode(r'''
 import 'package:meta/meta.dart';
@@ -83,7 +100,7 @@
     ]);
   }
 
-  test_constructorParam_redirectingConstructorCall() async {
+  test_constructor_redirectingConstructorCall() async {
     addMetaPackage();
     await assertErrorsInCode(r'''
 import 'package:meta/meta.dart';
@@ -96,7 +113,7 @@
     ]);
   }
 
-  test_constructorParam_superCall() async {
+  test_constructor_superCall() async {
     addMetaPackage();
     await assertErrorsInCode(r'''
 import 'package:meta/meta.dart';
@@ -113,7 +130,7 @@
     ]);
   }
 
-  test_functionParam() async {
+  test_function() async {
     addMetaPackage();
     await assertErrorsInCode(r'''
 import 'package:meta/meta.dart';
@@ -128,7 +145,7 @@
     ]);
   }
 
-  test_methodParam() async {
+  test_method() async {
     addMetaPackage();
     await assertErrorsInCode(r'''
 import 'package:meta/meta.dart';
@@ -143,7 +160,23 @@
     ]);
   }
 
-  test_methodParam_inOtherLib() async {
+  test_method_generic() async {
+    addMetaPackage();
+    await assertErrorsInCode(r'''
+import 'package:meta/meta.dart';
+
+class A<T> {
+  void m<U>(U a, {@Required('must specify an `b`') int b}) {}
+}
+f() {
+  new A<double>().m(true);
+}
+''', [
+      error(HintCode.MISSING_REQUIRED_PARAM_WITH_DETAILS, 135, 1),
+    ]);
+  }
+
+  test_method_inOtherLib() async {
     addMetaPackage();
     newFile('/a_lib.dart', content: r'''
 library a_lib;
@@ -170,7 +203,7 @@
 not know its elements, and does not know that there was a parameter
 marked `@required`. There is exactly one such typedef in Flutter.
 ''')
-  test_typedef_functionParam() async {
+  test_typedef_function() async {
     addMetaPackage();
     await assertErrorsInCode(r'''
 import 'package:meta/meta.dart';
@@ -202,7 +235,7 @@
     ..contextFeatures = new FeatureSet.forTesting(
         sdkVersion: '2.3.0', additionalFeatures: [Feature.non_nullable]);
 
-  test_constructorParam_argumentGiven() async {
+  test_constructor_argumentGiven() async {
     await assertNoErrorsInCode(r'''
 class C {
   C({required int a}) {}
@@ -214,7 +247,7 @@
 ''');
   }
 
-  test_constructorParam_missingArgument() async {
+  test_constructor_missingArgument() async {
     await assertErrorsInCode(r'''
 class C {
   C({required int a}) {}
@@ -227,7 +260,7 @@
     ]);
   }
 
-  test_constructorParam_redirectingConstructorCall() async {
+  test_constructor_redirectingConstructorCall() async {
     await assertErrorsInCode(r'''
 class C {
   C({required int x});
@@ -238,7 +271,7 @@
     ]);
   }
 
-  test_constructorParam_superCall() async {
+  test_constructor_superCall() async {
     await assertErrorsInCode(r'''
 class C {
   C({required int a}) {}
@@ -252,6 +285,18 @@
     ]);
   }
 
+  test_function() async {
+    await assertErrorsInCode(r'''
+void f({required int a}) {}
+
+main() {
+  f();
+}
+''', [
+      error(CompileTimeErrorCode.MISSING_REQUIRED_ARGUMENT, 40, 1),
+    ]);
+  }
+
   test_functionInvocation() async {
     await assertErrorsInCode(r'''
 void Function({required int a}) f() => throw '';
@@ -263,19 +308,7 @@
     ]);
   }
 
-  test_functionParam() async {
-    await assertErrorsInCode(r'''
-void f({required int a}) {}
-
-main() {
-  f();
-}
-''', [
-      error(CompileTimeErrorCode.MISSING_REQUIRED_ARGUMENT, 40, 1),
-    ]);
-  }
-
-  test_methodParam() async {
+  test_method() async {
     await assertErrorsInCode(r'''
 class A {
   void m({required int a}) {}
@@ -288,7 +321,7 @@
     ]);
   }
 
-  test_methodParam_inOtherLib() async {
+  test_method_inOtherLib() async {
     newFile('/test/lib/a_lib.dart', content: r'''
 class A {
   void m({required int a}) {}
@@ -304,7 +337,7 @@
     ]);
   }
 
-  test_typedef_functionParam() async {
+  test_typedef_function() async {
     await assertErrorsInCode(r'''
 String test(C c) => c.m()();
 
diff --git a/pkg/analyzer/test/src/diagnostics/must_be_a_subtype_test.dart b/pkg/analyzer/test/src/diagnostics/must_be_a_subtype_test.dart
new file mode 100644
index 0000000..f9e9334
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/must_be_a_subtype_test.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.
+
+import 'package:analyzer/src/dart/error/ffi_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(MustBeASubtypeTest);
+  });
+}
+
+@reflectiveTest
+class MustBeASubtypeTest extends DriverResolutionTest {
+  test_asFunction() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+typedef TPrime = int Function(int);
+typedef F = String Function(String);
+class C {
+  void f(Pointer<NativeFunction<TPrime>> p) {
+    p.asFunction<F>();
+  }
+}
+''', [
+      error(FfiCode.NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER, 165, 1),
+    ]);
+  }
+
+  test_fromFunction_firstArgument() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+typedef T = Int8 Function(Int8);
+String f(int i) => i.toString();
+void g() {
+  Pointer.fromFunction<T>(f, 5);
+}
+''', [
+      error(FfiCode.MUST_BE_A_SUBTYPE, 122, 1),
+    ]);
+  }
+
+  test_fromFunction_secondArgument() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+typedef T = Int8 Function(Int8);
+int f(int i) => i * 2;
+void g() {
+  Pointer.fromFunction<T>(f, '');
+}
+''', [
+      error(FfiCode.MUST_BE_A_SUBTYPE, 115, 2),
+    ]);
+  }
+
+  test_fromFunction_valid_oneArgument() async {
+    await assertNoErrorsInCode(r'''
+import 'dart:ffi';
+typedef T = Void Function(Int8);
+void f(int i) {}
+void g() {
+  Pointer.fromFunction<T>(f);
+}
+''');
+  }
+
+  test_fromFunction_valid_twoArguments() async {
+    await assertNoErrorsInCode(r'''
+import 'dart:ffi';
+typedef T = Int8 Function(Int8);
+int f(int i) => i * 2;
+void g() {
+  Pointer.fromFunction<T>(f, 42);
+}
+''');
+  }
+
+  test_lookupFunction() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+typedef S = int Function(int);
+typedef F = String Function(String);
+void f(DynamicLibrary lib) {
+  lib.lookupFunction<S, F>('g');
+}
+''', [
+      error(FfiCode.MUST_BE_A_NATIVE_FUNCTION_TYPE, 137, 1),
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/non_constant_type_argument_test.dart b/pkg/analyzer/test/src/diagnostics/non_constant_type_argument_test.dart
new file mode 100644
index 0000000..4b5275e
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/non_constant_type_argument_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/src/dart/error/ffi_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(NonConstantTypeArgumentTest);
+  });
+}
+
+@reflectiveTest
+class NonConstantTypeArgumentTest extends DriverResolutionTest {
+  test_asFunction_R() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+typedef T = int Function(int);
+class C<R extends int Function(int)> {
+  void f(Pointer<NativeFunction<T>> p) {
+    p.asFunction<R>();
+  }
+}
+''', [
+      error(FfiCode.NON_CONSTANT_TYPE_ARGUMENT, 147, 1),
+    ]);
+  }
+
+  test_fromFunction() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+int f(int i) => i * 2;
+class C<T extends Function> {
+  void g() {
+    Pointer.fromFunction<T>(f);
+  }
+}
+''', [
+      error(FfiCode.MUST_BE_A_NATIVE_FUNCTION_TYPE, 89, 26),
+    ]);
+  }
+
+  test_lookupFunction_F() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+typedef T = Int8 Function(Int8);
+class C<F extends int Function(int)> {
+  void f(DynamicLibrary lib, NativeFunction x) {
+    lib.lookupFunction<T, F>('g');
+  }
+}
+''', [
+      error(FfiCode.MUST_BE_A_SUBTYPE, 166, 1),
+    ]);
+  }
+
+  test_lookupFunction_T() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+typedef F = int Function(int);
+class C<T extends Function> {
+  void f(DynamicLibrary lib, NativeFunction x) {
+    lib.lookupFunction<T, F>('g');
+  }
+}
+''', [
+      error(FfiCode.MUST_BE_A_NATIVE_FUNCTION_TYPE, 152, 1),
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/non_constant_type_argument_to_pointer_test.dart b/pkg/analyzer/test/src/diagnostics/non_constant_type_argument_to_pointer_test.dart
new file mode 100644
index 0000000..a0aee94
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/non_constant_type_argument_to_pointer_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.
+
+import 'package:analyzer/src/dart/error/ffi_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(NonConstantTypeArgumentToPointerTest);
+  });
+}
+
+@reflectiveTest
+class NonConstantTypeArgumentToPointerTest extends DriverResolutionTest {
+  test_asFunction_F() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+typedef R = int Function(int);
+class C<T extends Function> {
+  void f(Pointer<NativeFunction<T>> p) {
+    p.asFunction<R>();
+  }
+}
+''', [
+      error(FfiCode.NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER, 138, 1),
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/non_native_function_type_argument_to_pointer_test.dart b/pkg/analyzer/test/src/diagnostics/non_native_function_type_argument_to_pointer_test.dart
new file mode 100644
index 0000000..ac8e808
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/non_native_function_type_argument_to_pointer_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.
+
+import 'package:analyzer/src/dart/error/ffi_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../dart/resolution/driver_resolution.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(NonNativeFunctionTypeArgumentToPointerTest);
+  });
+}
+
+@reflectiveTest
+class NonNativeFunctionTypeArgumentToPointerTest extends DriverResolutionTest {
+  test_asFunction() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+typedef R = Int8 Function(Int8);
+class C {
+  void f(Pointer<Double> p) {
+    p.asFunction<R>();
+  }
+}
+''', [
+      error(FfiCode.NON_NATIVE_FUNCTION_TYPE_ARGUMENT_TO_POINTER, 109, 1),
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/subtype_of_ffi_class_test.dart b/pkg/analyzer/test/src/diagnostics/subtype_of_ffi_class_test.dart
new file mode 100644
index 0000000..e13d224
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/subtype_of_ffi_class_test.dart
@@ -0,0 +1,407 @@
+// 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/dart/error/ffi_code.dart';
+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(SubtypeOfFfiClassInExtendsTest);
+    defineReflectiveTests(SubtypeOfFfiClassInImplementsTest);
+    defineReflectiveTests(SubtypeOfFfiClassInWithTest);
+  });
+}
+
+@reflectiveTest
+class SubtypeOfFfiClassInExtendsTest extends DriverResolutionTest {
+  test_Double() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Double {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_EXTENDS, 35, 6),
+    ]);
+  }
+
+  test_Float() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Float {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_EXTENDS, 35, 5),
+    ]);
+  }
+
+  test_Int16() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Int16 {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_EXTENDS, 35, 5),
+    ]);
+  }
+
+  test_Int32() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Int32 {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_EXTENDS, 35, 5),
+    ]);
+  }
+
+  test_Int64() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Int64 {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_EXTENDS, 35, 5),
+    ]);
+  }
+
+  test_Int8() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Int8 {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_EXTENDS, 35, 4),
+    ]);
+  }
+
+  test_Pointer() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Pointer {}
+''', [
+      // TODO(brianwilkerson) The following diagnostic should not be generated.
+      error(StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE,
+          25, 1),
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_EXTENDS, 35, 7),
+    ]);
+  }
+
+  test_Struct() async {
+    await assertNoErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Struct {}
+''');
+  }
+
+  test_Uint16() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Uint16 {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_EXTENDS, 35, 6),
+    ]);
+  }
+
+  test_Uint32() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Uint32 {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_EXTENDS, 35, 6),
+    ]);
+  }
+
+  test_Uint64() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Uint64 {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_EXTENDS, 35, 6),
+    ]);
+  }
+
+  test_Uint8() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Uint8 {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_EXTENDS, 35, 5),
+    ]);
+  }
+
+  test_Void() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C extends Void {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_EXTENDS, 35, 4),
+    ]);
+  }
+}
+
+@reflectiveTest
+class SubtypeOfFfiClassInImplementsTest extends DriverResolutionTest {
+  test_Double() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C implements Double {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_IMPLEMENTS, 38, 6),
+    ]);
+  }
+
+  test_Float() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C implements Float {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_IMPLEMENTS, 38, 5),
+    ]);
+  }
+
+  test_Int16() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C implements Int16 {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_IMPLEMENTS, 38, 5),
+    ]);
+  }
+
+  test_Int32() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C implements Int32 {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_IMPLEMENTS, 38, 5),
+    ]);
+  }
+
+  test_Int64() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C implements Int64 {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_IMPLEMENTS, 38, 5),
+    ]);
+  }
+
+  test_Int8() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C implements Int8 {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_IMPLEMENTS, 38, 4),
+    ]);
+  }
+
+  test_Pointer() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C implements Pointer {}
+''', [
+      // TODO(brianwilkerson) The following diagnostic should not be generated.
+      error(StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE,
+          25, 1),
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_IMPLEMENTS, 38, 7),
+    ]);
+  }
+
+  test_Struct() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C implements Struct {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_IMPLEMENTS, 38, 6),
+    ]);
+  }
+
+  test_Uint16() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C implements Uint16 {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_IMPLEMENTS, 38, 6),
+    ]);
+  }
+
+  test_Uint32() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C implements Uint32 {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_IMPLEMENTS, 38, 6),
+    ]);
+  }
+
+  test_Uint64() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C implements Uint64 {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_IMPLEMENTS, 38, 6),
+    ]);
+  }
+
+  test_Uint8() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C implements Uint8 {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_IMPLEMENTS, 38, 5),
+    ]);
+  }
+
+  test_Void() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C implements Void {}
+''', [
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_IMPLEMENTS, 38, 4),
+    ]);
+  }
+}
+
+@reflectiveTest
+class SubtypeOfFfiClassInWithTest extends DriverResolutionTest {
+  test_Double() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C with Double {}
+''', [
+      error(CompileTimeErrorCode.MIXIN_CLASS_DECLARES_CONSTRUCTOR, 32, 6),
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 32, 6),
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_WITH, 32, 6),
+    ]);
+  }
+
+  test_Float() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C with Float {}
+''', [
+      error(CompileTimeErrorCode.MIXIN_CLASS_DECLARES_CONSTRUCTOR, 32, 5),
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 32, 5),
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_WITH, 32, 5),
+    ]);
+  }
+
+  test_Int16() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C with Int16 {}
+''', [
+      error(CompileTimeErrorCode.MIXIN_CLASS_DECLARES_CONSTRUCTOR, 32, 5),
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 32, 5),
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_WITH, 32, 5),
+    ]);
+  }
+
+  test_Int32() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C with Int32 {}
+''', [
+      error(CompileTimeErrorCode.MIXIN_CLASS_DECLARES_CONSTRUCTOR, 32, 5),
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 32, 5),
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_WITH, 32, 5),
+    ]);
+  }
+
+  test_Int64() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C with Int64 {}
+''', [
+      error(CompileTimeErrorCode.MIXIN_CLASS_DECLARES_CONSTRUCTOR, 32, 5),
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 32, 5),
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_WITH, 32, 5),
+    ]);
+  }
+
+  test_Int8() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C with Int8 {}
+''', [
+      error(CompileTimeErrorCode.MIXIN_CLASS_DECLARES_CONSTRUCTOR, 32, 4),
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 32, 4),
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_WITH, 32, 4),
+    ]);
+  }
+
+  test_Pointer() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C with Pointer {}
+''', [
+      // TODO(brianwilkerson) The following diagnostic should not be generated.
+      error(StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE,
+          25, 1),
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 32, 7),
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_WITH, 32, 7),
+    ]);
+  }
+
+  test_Struct() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C with Struct {}
+''', [
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 32, 6),
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_WITH, 32, 6),
+    ]);
+  }
+
+  test_Uint16() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C with Uint16 {}
+''', [
+      error(CompileTimeErrorCode.MIXIN_CLASS_DECLARES_CONSTRUCTOR, 32, 6),
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 32, 6),
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_WITH, 32, 6),
+    ]);
+  }
+
+  test_Uint32() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C with Uint32 {}
+''', [
+      error(CompileTimeErrorCode.MIXIN_CLASS_DECLARES_CONSTRUCTOR, 32, 6),
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 32, 6),
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_WITH, 32, 6),
+    ]);
+  }
+
+  test_Uint64() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C with Uint64 {}
+''', [
+      error(CompileTimeErrorCode.MIXIN_CLASS_DECLARES_CONSTRUCTOR, 32, 6),
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 32, 6),
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_WITH, 32, 6),
+    ]);
+  }
+
+  test_Uint8() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C with Uint8 {}
+''', [
+      error(CompileTimeErrorCode.MIXIN_CLASS_DECLARES_CONSTRUCTOR, 32, 5),
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 32, 5),
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_WITH, 32, 5),
+    ]);
+  }
+
+  test_Void() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class C with Void {}
+''', [
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 32, 4),
+      error(FfiCode.SUBTYPE_OF_FFI_CLASS_IN_WITH, 32, 4),
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/subtype_of_struct_class_test.dart b/pkg/analyzer/test/src/diagnostics/subtype_of_struct_class_test.dart
new file mode 100644
index 0000000..0c5b17e
--- /dev/null
+++ b/pkg/analyzer/test/src/diagnostics/subtype_of_struct_class_test.dart
@@ -0,0 +1,57 @@
+// 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/dart/error/ffi_code.dart';
+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(SubtypeOfStructClassInExtendsTest);
+    defineReflectiveTests(SubtypeOfStructClassInImplementsTest);
+    defineReflectiveTests(SubtypeOfStructClassInWithTest);
+  });
+}
+
+@reflectiveTest
+class SubtypeOfStructClassInExtendsTest extends DriverResolutionTest {
+  test_extends() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class S extends Struct {}
+class C extends S {}
+''', [
+      error(FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_EXTENDS, 61, 1),
+    ]);
+  }
+}
+
+@reflectiveTest
+class SubtypeOfStructClassInImplementsTest extends DriverResolutionTest {
+  test_implements() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class S extends Struct {}
+class C implements S {}
+''', [
+      error(FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_IMPLEMENTS, 64, 1),
+    ]);
+  }
+}
+
+@reflectiveTest
+class SubtypeOfStructClassInWithTest extends DriverResolutionTest {
+  test_with() async {
+    await assertErrorsInCode(r'''
+import 'dart:ffi';
+class S extends Struct {}
+class C with S {}
+''', [
+      error(CompileTimeErrorCode.MIXIN_INHERITS_FROM_NOT_OBJECT, 58, 1),
+      error(FfiCode.SUBTYPE_OF_STRUCT_CLASS_IN_WITH, 58, 1),
+    ]);
+  }
+}
diff --git a/pkg/analyzer/test/src/diagnostics/test_all.dart b/pkg/analyzer/test/src/diagnostics/test_all.dart
index 71bef09..a46bc359 100644
--- a/pkg/analyzer/test/src/diagnostics/test_all.dart
+++ b/pkg/analyzer/test/src/diagnostics/test_all.dart
@@ -9,6 +9,7 @@
     as ambiguous_extension_member_access;
 import 'ambiguous_import_test.dart' as ambiguous_import;
 import 'ambiguous_set_or_map_literal_test.dart' as ambiguous_set_or_map_literal;
+import 'annotation_on_pointer_field_test.dart' as annotation_on_pointer_field;
 import 'argument_type_not_assignable_test.dart' as argument_type_not_assignable;
 import 'assert_in_redirecting_constructor_test.dart'
     as assert_in_redirecting_constructor;
@@ -85,9 +86,14 @@
     as extension_override_with_cascade;
 import 'extension_override_without_access_test.dart'
     as extension_override_without_access;
+import 'extra_annotation_on_struct_field_test.dart'
+    as extra_annotation_on_struct_field;
 import 'extra_positional_arguments_test.dart' as extra_positional_arguments;
+import 'field_in_struct_with_initializer_test.dart'
+    as field_in_struct_with_initializer;
 import 'field_initialized_in_initializer_and_declaration_test.dart'
     as field_initialized_in_initializer_and_declaration;
+import 'field_initializer_in_struct_test.dart' as field_initializer_in_struct;
 import 'field_initializer_not_assignable_test.dart'
     as field_initializer_not_assignable;
 import 'field_initializing_formal_not_assignable_test.dart'
@@ -97,6 +103,7 @@
 import 'final_not_initialized_constructor_test.dart'
     as final_not_initialized_constructor;
 import 'final_not_initialized_test.dart' as final_not_initialized;
+import 'generic_struct_subclass_test.dart' as generic_struct_subclass;
 import 'if_element_condition_from_deferred_library_test.dart'
     as if_element_condition_from_deferred_library;
 import 'implements_non_class_test.dart' as implements_non_class;
@@ -119,10 +126,12 @@
     as instance_access_to_static_member;
 import 'invalid_assignment_test.dart' as invalid_assignment;
 import 'invalid_cast_new_expr_test.dart' as invalid_cast_new_expr;
+import 'invalid_exception_value_test.dart' as invalid_exception_value;
 import 'invalid_extension_argument_count_test.dart'
     as invalid_extension_argument_count;
 import 'invalid_factory_annotation_test.dart' as invalid_factory_annotation;
 import 'invalid_factory_method_impl_test.dart' as invalid_factory_method_impl;
+import 'invalid_field_type_in_struct_test.dart' as invalid_field_type_in_struct;
 import 'invalid_immutable_annotation_test.dart' as invalid_immutable_annotation;
 import 'invalid_literal_annotation_test.dart' as invalid_literal_annotation;
 import 'invalid_optional_parameter_type_test.dart'
@@ -163,11 +172,17 @@
 import 'map_key_type_not_assignable_test.dart' as map_key_type_not_assignable;
 import 'map_value_type_not_assignable_test.dart'
     as map_value_type_not_assignable;
+import 'mismatched_annotation_on_struct_field_test.dart'
+    as mismatched_annotation_on_struct_field;
 import 'mismatched_getter_and_setter_types_test.dart'
     as mismatched_getter_and_setter_types;
+import 'missing_annotation_on_struct_field_test.dart'
+    as missing_annotation_on_struct_field;
 import 'missing_default_value_for_parameter_test.dart'
     as missing_default_value_for_parameter;
 import 'missing_enum_value_in_switch_test.dart' as missing_enum_value_in_switch;
+import 'missing_exception_value_test.dart' as missing_exception_value;
+import 'missing_field_type_in_struct_test.dart' as missing_field_type_in_struct;
 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;
@@ -176,6 +191,7 @@
 import 'mixin_on_sealed_class_test.dart' as mixin_on_sealed_class;
 import 'mixin_super_class_constraint_non_interface_test.dart'
     as mixin_super_class_constraint_non_interface;
+import 'must_be_a_subtype_test.dart' as must_be_a_subtype;
 import 'must_be_immutable_test.dart' as must_be_immutable;
 import 'must_call_super_test.dart' as must_call_super;
 import 'new_with_abstract_class_test.dart' as new_with_abstract_class;
@@ -200,6 +216,11 @@
     as non_constant_map_value_from_deferred_library;
 import 'non_constant_map_value_test.dart' as non_constant_map_value;
 import 'non_constant_set_element_test.dart' as non_constant_set_element;
+import 'non_constant_type_argument_test.dart' as non_constant_type_argument;
+import 'non_constant_type_argument_to_pointer_test.dart'
+    as non_constant_type_argument_to_pointer;
+import 'non_native_function_type_argument_to_pointer_test.dart'
+    as non_native_function_type_argument_to_pointer;
 import 'non_null_opt_out_test.dart' as non_null_opt_out;
 import 'non_type_in_catch_clause_test.dart' as non_type_in_catch_clause;
 import 'non_void_return_for_operator_test.dart' as non_void_return_for_operator;
@@ -274,7 +295,9 @@
 import 'static_access_to_instance_member_test.dart'
     as static_access_to_instance_member;
 import 'strict_raw_type_test.dart' as strict_raw_type;
+import 'subtype_of_ffi_class_test.dart' as subtype_of_ffi_class;
 import 'subtype_of_sealed_class_test.dart' as subtype_of_sealed_class;
+import 'subtype_of_struct_class_test.dart' as subtype_of_struct_class;
 import 'super_in_extension_test.dart' as super_in_extension;
 import 'switch_expression_not_assignable_test.dart'
     as switch_expression_not_assignable;
@@ -339,6 +362,7 @@
     ambiguous_extension_member_access.main();
     ambiguous_import.main();
     ambiguous_set_or_map_literal.main();
+    annotation_on_pointer_field.main();
     argument_type_not_assignable.main();
     assert_in_redirecting_constructor.main();
     assignment_to_const.main();
@@ -392,13 +416,17 @@
     extension_override_argument_not_assignable.main();
     extension_override_with_cascade.main();
     extension_override_without_access.main();
+    extra_annotation_on_struct_field.main();
     extra_positional_arguments.main();
+    field_in_struct_with_initializer.main();
     field_initialized_in_initializer_and_declaration.main();
+    field_initializer_in_struct.main();
     field_initializer_not_assignable.main();
     field_initializing_formal_not_assignable.main();
     final_initialized_in_delcaration_and_constructor.main();
     final_not_initialized_constructor.main();
     final_not_initialized.main();
+    generic_struct_subclass.main();
     if_element_condition_from_deferred_library.main();
     implements_non_class.main();
     implicit_this_reference_in_initializer.main();
@@ -412,9 +440,11 @@
     instance_access_to_static_member.main();
     invalid_assignment.main();
     invalid_cast_new_expr.main();
+    invalid_exception_value.main();
     invalid_extension_argument_count.main();
     invalid_factory_annotation.main();
     invalid_factory_method_impl.main();
+    invalid_field_type_in_struct.main();
     invalid_immutable_annotation.main();
     invalid_literal_annotation.main();
     invalid_optional_parameter_type.main();
@@ -442,9 +472,13 @@
     map_entry_not_in_map.main();
     map_key_type_not_assignable.main();
     map_value_type_not_assignable.main();
+    mismatched_annotation_on_struct_field.main();
     mismatched_getter_and_setter_types.main();
+    missing_annotation_on_struct_field.main();
     missing_default_value_for_parameter.main();
     missing_enum_value_in_switch.main();
+    missing_exception_value.main();
+    missing_field_type_in_struct.main();
     missing_js_lib_annotation.main();
     missing_required_param.main();
     missing_return.main();
@@ -452,6 +486,7 @@
     mixin_of_non_class.main();
     mixin_on_sealed_class.main();
     mixin_super_class_constraint_non_interface.main();
+    must_be_a_subtype.main();
     must_be_immutable.main();
     must_call_super.main();
     new_with_abstract_class.main();
@@ -470,6 +505,9 @@
     non_constant_map_value.main();
     non_constant_map_value_from_deferred_library.main();
     non_constant_set_element.main();
+    non_constant_type_argument.main();
+    non_constant_type_argument_to_pointer.main();
+    non_native_function_type_argument_to_pointer.main();
     non_null_opt_out.main();
     non_type_in_catch_clause.main();
     non_void_return_for_operator.main();
@@ -517,7 +555,9 @@
     spread_expression_from_deferred_library.main();
     static_access_to_instance_member.main();
     strict_raw_type.main();
+    subtype_of_ffi_class.main();
     subtype_of_sealed_class.main();
+    subtype_of_struct_class.main();
     super_in_extension.main();
     switch_expression_not_assignable.main();
     top_level_instance_getter.main();
diff --git a/pkg/analyzer/test/src/diagnostics/undefined_identifier_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_identifier_test.dart
index 64d01e9..84a31f0 100644
--- a/pkg/analyzer/test/src/diagnostics/undefined_identifier_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/undefined_identifier_test.dart
@@ -2,7 +2,9 @@
 // for 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';
@@ -10,6 +12,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(UndefinedIdentifierTest);
+    defineReflectiveTests(UndefinedIdentifierWithNnbdTest);
   });
 }
 
@@ -147,3 +150,18 @@
     ]);
   }
 }
+
+@reflectiveTest
+class UndefinedIdentifierWithNnbdTest extends UndefinedIdentifierTest {
+  @override
+  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/variable_type_mismatch_test.dart b/pkg/analyzer/test/src/diagnostics/variable_type_mismatch_test.dart
index 1cd6641..8a32470 100644
--- a/pkg/analyzer/test/src/diagnostics/variable_type_mismatch_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/variable_type_mismatch_test.dart
@@ -17,7 +17,6 @@
 /// to this class.
 @reflectiveTest
 class VariableTypeMismatchTest extends DriverResolutionTest {
-  @FailingTest(reason: 'Workaround for #35993 is too broad')
   test_int_to_double_variable_reference_is_not_promoted() async {
     // Note: in the following code, the declaration of `y` should produce an
     // error because we should only promote literal ints to doubles; we
diff --git a/pkg/analyzer/test/src/summary/resolved_ast_printer.dart b/pkg/analyzer/test/src/summary/resolved_ast_printer.dart
index 93a5e30..faa8571 100644
--- a/pkg/analyzer/test/src/summary/resolved_ast_printer.dart
+++ b/pkg/analyzer/test/src/summary/resolved_ast_printer.dart
@@ -3,30 +3,63 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/token.dart';
 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/element/element.dart';
 import 'package:analyzer/src/dart/element/member.dart';
+import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/summary2/reference.dart';
 import 'package:meta/meta.dart';
 
+/// Used in [ResolvedAstPrinter] to print lines of code that corresponding
+/// to a subtree of AST. This help to make the bulky presentation of AST a
+/// bit more understandable.
+abstract class CodeLinesProvider {
+  /// If the [offset] corresponds to a new, never requested before line,
+  /// return this line, otherwise return `null`.
+  String nextLine(int offset);
+}
+
 /// Prints AST as a tree, with properties and children.
 class ResolvedAstPrinter extends ThrowingAstVisitor<void> {
+  /// The URI of the library that contains the AST being printed.
   final String _selfUriStr;
+
+  /// The target sink to print AST.
   final StringSink _sink;
+
+  /// The optional provider for code lines, might be `null`.
+  final CodeLinesProvider _codeLinesProvider;
+
   String _indent = '';
 
   ResolvedAstPrinter({
     @required String selfUriStr,
     @required StringSink sink,
     @required String indent,
+    CodeLinesProvider codeLinesProvider,
   })  : _selfUriStr = selfUriStr,
         _sink = sink,
+        _codeLinesProvider = codeLinesProvider,
         _indent = indent;
 
   @override
+  void visitAdjacentStrings(AdjacentStrings node) {
+    _writeNextCodeLine(node);
+    _writeln('AdjacentStrings');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNodeList('strings', node.strings);
+      _addStringLiteral(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
   void visitAnnotation(Annotation node) {
+    _writeNextCodeLine(node);
     _writeln('Annotation');
     _withIndent(() {
       _writeNode('arguments', node.arguments);
@@ -38,6 +71,7 @@
 
   @override
   void visitArgumentList(ArgumentList node) {
+    _writeNextCodeLine(node);
     _writeln('ArgumentList');
     _withIndent(() {
       _writeNodeList('arguments', node.arguments);
@@ -45,12 +79,259 @@
   }
 
   @override
+  void visitAsExpression(AsExpression node) {
+    _writeNextCodeLine(node);
+    _writeln('AsExpression');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('expression', node.expression);
+      properties.addNode('type', node.type);
+      _addExpression(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitAssertInitializer(AssertInitializer node) {
+    _writeNextCodeLine(node);
+    _writeln('AssertInitializer');
+    _withIndent(() {
+      var properties = _Properties();
+      _addAssertion(properties, node);
+      _addConstructorInitializer(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitAssertStatement(AssertStatement node) {
+    _writeNextCodeLine(node);
+    _writeln('AssertStatement');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('semicolon', node.semicolon);
+      _addAssertion(properties, node);
+      _addStatement(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitAssignmentExpression(AssignmentExpression node) {
+    _writeNextCodeLine(node);
+    _writeln('AssignmentExpression');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('leftHandSide', node.leftHandSide);
+      properties.addToken('operator', node.operator);
+      properties.addNode('rightHandSide', node.rightHandSide);
+      _addExpression(properties, node);
+      _addMethodReferenceExpression(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitAwaitExpression(AwaitExpression node) {
+    _writeNextCodeLine(node);
+    _writeln('AwaitExpression');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('awaitKeyword', node.awaitKeyword);
+      properties.addNode('expression', node.expression);
+      _addExpression(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitBinaryExpression(BinaryExpression node) {
+    _writeNextCodeLine(node);
+    _writeln('BinaryExpression');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('leftOperand', node.leftOperand);
+      properties.addToken('operator', node.operator);
+      properties.addNode('rightOperand', node.rightOperand);
+      properties.addType('staticInvokeType', node.staticInvokeType);
+      _addExpression(properties, node);
+      _addMethodReferenceExpression(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitBlock(Block node) {
+    _writeNextCodeLine(node);
+    _writeln('Block');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNodeList('statements', node.statements);
+      _addStatement(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitBlockFunctionBody(BlockFunctionBody node) {
+    _writeNextCodeLine(node);
+    _writeln('BlockFunctionBody');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('block', node.block);
+      _addFunctionBody(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitBooleanLiteral(BooleanLiteral node) {
+    _writeNextCodeLine(node);
+    _writeln('BooleanLiteral');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('literal', node.literal);
+      _addLiteral(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitBreakStatement(BreakStatement node) {
+    _writeNextCodeLine(node);
+    _writeln('BreakStatement');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('breakKeyword', node.breakKeyword);
+      properties.addNode('label', node.label);
+      _addStatement(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitCascadeExpression(CascadeExpression node) {
+    _writeNextCodeLine(node);
+    _writeln('CascadeExpression');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNodeList('cascadeSections', node.cascadeSections);
+      properties.addNode('target', node.target);
+      _addExpression(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitCatchClause(CatchClause node) {
+    _writeNextCodeLine(node);
+    _writeln('CatchClause');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('body', node.body);
+      properties.addToken('catchKeyword', node.catchKeyword);
+      properties.addNode('exceptionParameter', node.exceptionParameter);
+      properties.addNode('exceptionType', node.exceptionType);
+      properties.addToken('onKeyword', node.onKeyword);
+      properties.addNode('stackTraceParameter', node.stackTraceParameter);
+      _addAstNode(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitClassDeclaration(ClassDeclaration node) {
+    _writeNextCodeLine(node);
+    _writeln('ClassDeclaration');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('abstractKeyword', node.abstractKeyword);
+      properties.addToken('classKeyword', node.classKeyword);
+      properties.addNode('extendsClause', node.extendsClause);
+      properties.addNode('nativeClause', node.nativeClause);
+      properties.addNode('withClause', node.withClause);
+      _addClassOrMixinDeclaration(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitComment(Comment node) {
+    _writeNextCodeLine(node);
+    _writeln('Comment');
+    _withIndent(() {
+      var properties = _Properties();
+      _addAstNode(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
   void visitCompilationUnit(CompilationUnit node) {
-    super.visitCompilationUnit(node);
+    _writeNextCodeLine(node);
+    _writeln('CompilationUnit');
+    _withIndent(() {
+      _writeNode('scriptTag', node.scriptTag);
+      _writeNodeList('directives', node.directives);
+      _writeNodeList('declarations', node.declarations);
+    });
+  }
+
+  @override
+  void visitConditionalExpression(ConditionalExpression node) {
+    _writeNextCodeLine(node);
+    _writeln('ConditionalExpression');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('colon', node.colon);
+      properties.addNode('condition', node.condition);
+      properties.addNode('elseExpression', node.elseExpression);
+      properties.addToken('question', node.question);
+      properties.addNode('thenExpression', node.thenExpression);
+      _addExpression(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitConstructorDeclaration(ConstructorDeclaration node) {
+    _writeNextCodeLine(node);
+    _writeln('ConstructorDeclaration');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('body', node.body);
+      properties.addToken('constKeyword', node.constKeyword);
+      properties.addToken('externalKeyword', node.externalKeyword);
+      properties.addToken('factoryKeyword', node.factoryKeyword);
+      properties.addNodeList('initializers', node.initializers);
+      properties.addNode('name', node.name);
+      properties.addNode('parameters', node.parameters);
+      properties.addNode('redirectedConstructor', node.redirectedConstructor);
+      properties.addNode('returnType', node.returnType);
+      _addClassMember(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
+    _writeNextCodeLine(node);
+    _writeln('ConstructorFieldInitializer');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('equals', node.equals);
+      properties.addNode('expression', node.expression);
+      properties.addNode('fieldName', node.fieldName);
+      properties.addToken('period', node.period);
+      properties.addToken('thisKeyword', node.thisKeyword);
+      _addConstructorInitializer(properties, node);
+      _writeProperties(properties);
+    });
   }
 
   @override
   void visitConstructorName(ConstructorName node) {
+    _writeNextCodeLine(node);
     _writeln('ConstructorName');
     _withIndent(() {
       _writeNode('name', node.name);
@@ -59,32 +340,742 @@
   }
 
   @override
+  void visitContinueStatement(ContinueStatement node) {
+    _writeNextCodeLine(node);
+    _writeln('ContinueStatement');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('continueKeyword', node.continueKeyword);
+      properties.addNode('label', node.label);
+      _addStatement(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitDeclaredIdentifier(DeclaredIdentifier node) {
+    _writeNextCodeLine(node);
+    _writeln('DeclaredIdentifier');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('identifier', node.identifier);
+      properties.addToken('keyword', node.keyword);
+      properties.addNode('type', node.type);
+      _addDeclaration(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitDefaultFormalParameter(DefaultFormalParameter node) {
+    _writeNextCodeLine(node);
+    _writeln('DefaultFormalParameter');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('defaultValue', node.defaultValue);
+      properties.addNode('parameter', node.parameter);
+      _addFormalParameter(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitDoStatement(DoStatement node) {
+    _writeNextCodeLine(node);
+    _writeln('DoStatement');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('body', node.body);
+      properties.addNode('condition', node.condition);
+      _addStatement(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitDoubleLiteral(DoubleLiteral node) {
+    _writeNextCodeLine(node);
+    _writeln('DoubleLiteral');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('literal', node.literal);
+      _addLiteral(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitEmptyFunctionBody(EmptyFunctionBody node) {
+    _writeNextCodeLine(node);
+    _writeln('EmptyFunctionBody');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('semicolon', node.semicolon);
+      _addFunctionBody(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitEnumConstantDeclaration(EnumConstantDeclaration node) {
+    _writeNextCodeLine(node);
+    _writeln('EnumConstantDeclaration');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('name', node.name);
+      _addDeclaration(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitEnumDeclaration(EnumDeclaration node) {
+    _writeNextCodeLine(node);
+    _writeln('EnumDeclaration');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNodeList('constants', node.constants);
+      _addNamedCompilationUnitMember(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitExportDirective(ExportDirective node) {
+    _writeNextCodeLine(node);
+    _writeln('ExportDirective');
+    _withIndent(() {
+      var properties = _Properties();
+      _addNamespaceDirective(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitExpressionFunctionBody(ExpressionFunctionBody node) {
+    _writeNextCodeLine(node);
+    _writeln('ExpressionFunctionBody');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('expression', node.expression);
+      properties.addToken('functionDefinition', node.functionDefinition);
+      properties.addToken('semicolon', node.semicolon);
+      _addFunctionBody(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitExpressionStatement(ExpressionStatement node) {
+    _writeNextCodeLine(node);
+    _writeln('ExpressionStatement');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('expression', node.expression);
+      properties.addToken('semicolon', node.semicolon);
+      _addStatement(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitExtendsClause(ExtendsClause node) {
+    _writeNextCodeLine(node);
+    _writeln('ExtendsClause');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('superclass', node.superclass);
+      _addAstNode(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitFieldDeclaration(FieldDeclaration node) {
+    _writeNextCodeLine(node);
+    _writeln('FieldDeclaration');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('covariantKeyword', node.covariantKeyword);
+      properties.addNode('fields', node.fields);
+      properties.addToken('semicolon', node.semicolon);
+      properties.addToken('staticKeyword', node.staticKeyword);
+      _addClassMember(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitFieldFormalParameter(FieldFormalParameter node) {
+    _writeNextCodeLine(node);
+    _writeln('FieldFormalParameter');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('keyword', node.keyword);
+      properties.addNode('parameters', node.parameters);
+      properties.addToken('thisKeyword', node.thisKeyword);
+      properties.addNode('type', node.type);
+      properties.addNode('typeParameters', node.typeParameters);
+      _addNormalFormalParameter(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitForEachPartsWithDeclaration(ForEachPartsWithDeclaration node) {
+    _writeNextCodeLine(node);
+    _writeln('ForEachPartsWithDeclaration');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('loopVariable', node.loopVariable);
+      _addForEachParts(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitForEachPartsWithIdentifier(ForEachPartsWithIdentifier node) {
+    _writeNextCodeLine(node);
+    _writeln('ForEachPartsWithIdentifier');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('identifier', node.identifier);
+      _addForEachParts(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitFormalParameterList(FormalParameterList node) {
+    _writeNextCodeLine(node);
+    _writeln('FormalParameterList');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNodeList('parameters', node.parameters);
+      _addAstNode(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitForPartsWithDeclarations(ForPartsWithDeclarations node) {
+    _writeNextCodeLine(node);
+    _writeln('ForPartsWithDeclarations');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('variables', node.variables);
+      _addForParts(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitForPartsWithExpression(ForPartsWithExpression node) {
+    _writeNextCodeLine(node);
+    _writeln('ForPartsWithExpression');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('initialization', node.initialization);
+      _addForParts(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitForStatement(ForStatement node) {
+    _writeNextCodeLine(node);
+    _writeln('ForStatement');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('body', node.body);
+      properties.addNode('forLoopParts', node.forLoopParts);
+      _addStatement(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitFunctionDeclaration(FunctionDeclaration node) {
+    _writeNextCodeLine(node);
+    _writeln('FunctionDeclaration');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addType('declaredElementType', node.declaredElement.type);
+      properties.addToken('externalKeyword', node.externalKeyword);
+      properties.addNode('functionExpression', node.functionExpression);
+      properties.addToken('propertyKeyword', node.propertyKeyword);
+      properties.addNode('returnType', node.returnType);
+      _addNamedCompilationUnitMember(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
+    _writeNextCodeLine(node);
+    _writeln('FunctionDeclarationStatement');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('functionDeclaration', node.functionDeclaration);
+      _addStatement(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitFunctionExpression(FunctionExpression node) {
+    _writeNextCodeLine(node);
+    _writeln('FunctionExpression');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('body', node.body);
+      properties.addElement('declaredElement', node.declaredElement);
+      properties.addNode('parameters', node.parameters);
+      properties.addNode('typeParameters', node.typeParameters);
+      _addExpression(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
+    _writeNextCodeLine(node);
+    _writeln('FunctionExpressionInvocation');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('function', node.function);
+      properties.addElement('staticElement', node.staticElement);
+      _addInvocationExpression(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitFunctionTypeAlias(FunctionTypeAlias node) {
+    _writeNextCodeLine(node);
+    _writeln('FunctionTypeAlias');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addElement('declaredElement', node.declaredElement);
+      properties.addNode('parameters', node.parameters);
+      properties.addNode('returnType', node.returnType);
+      properties.addNode('typeParameters', node.typeParameters);
+      _addTypeAlias(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
+    _writeNextCodeLine(node);
+    _writeln('FunctionTypedFormalParameter');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('parameters', node.parameters);
+      properties.addToken('question', node.question);
+      properties.addNode('returnType', node.returnType);
+      properties.addNode('typeParameters', node.typeParameters);
+      _addNormalFormalParameter(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitGenericFunctionType(GenericFunctionType node) {
+    _writeNextCodeLine(node);
+    _writeln('GenericFunctionType');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('functionKeyword', node.functionKeyword);
+      properties.addNode('parameters', node.parameters);
+      properties.addNode('returnType', node.returnType);
+      properties.addNode('typeParameters', node.typeParameters);
+      _addTypeAnnotation(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitGenericTypeAlias(GenericTypeAlias node) {
+    _writeNextCodeLine(node);
+    _writeln('GenericTypeAlias');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('equals', node.equals);
+      properties.addNode('functionType', node.functionType);
+      properties.addNode('typeParameters', node.typeParameters);
+      _addTypeAlias(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitHideCombinator(HideCombinator node) {
+    _writeNextCodeLine(node);
+    _writeln('HideCombinator');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNodeList('hiddenNames', node.hiddenNames);
+      _addCombinator(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitIfStatement(IfStatement node) {
+    _writeNextCodeLine(node);
+    _writeln('IfStatement');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('condition', node.condition);
+      properties.addNode('elseStatement', node.elseStatement);
+      properties.addNode('thenStatement', node.thenStatement);
+      _addStatement(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitImplementsClause(ImplementsClause node) {
+    _writeNextCodeLine(node);
+    _writeln('ImplementsClause');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('implementsKeyword', node.implementsKeyword);
+      properties.addNodeList('interfaces', node.interfaces);
+      _addAstNode(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitImportDirective(ImportDirective node) {
+    _writeNextCodeLine(node);
+    _writeln('ImportDirective');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('prefix', node.prefix);
+      _addNamespaceDirective(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitIndexExpression(IndexExpression node) {
+    _writeNextCodeLine(node);
+    _writeln('IndexExpression');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addAuxiliaryElements(
+        'auxiliaryElements',
+        node.auxiliaryElements,
+      );
+      properties.addNode('index', node.index);
+      properties.addToken('period', node.period);
+      properties.addNode('target', node.target);
+      _addExpression(properties, node);
+      _addMethodReferenceExpression(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
   void visitInstanceCreationExpression(InstanceCreationExpression node) {
+    _writeNextCodeLine(node);
     _writeln('InstanceCreationExpression');
     _withIndent(() {
-      _writeNode('argumentList', node.argumentList);
-      _writeNode('constructorName', node.constructorName);
-      _writeElement('staticElement', node.staticElement);
-      _writeType('staticType', node.staticType);
+      var properties = _Properties();
+      properties.addNode('argumentList', node.argumentList);
+      properties.addNode('constructorName', node.constructorName);
+      properties.addToken('keyword', node.keyword);
+      _addExpression(properties, node);
+      _addConstructorReferenceNode(properties, node);
+      _writeProperties(properties);
     });
   }
 
   @override
   void visitIntegerLiteral(IntegerLiteral node) {
+    _writeNextCodeLine(node);
     _writeln('IntegerLiteral');
     _withIndent(() {
-      _writelnWithIndent('literal: ${node.literal}');
-      _writeType('staticType', node.staticType);
+      var properties = _Properties();
+      properties.addToken('literal', node.literal);
+      _addLiteral(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitInterpolationExpression(InterpolationExpression node) {
+    _writeNextCodeLine(node);
+    _writeln('InterpolationExpression');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('expression', node.expression);
+      _addInterpolationElement(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitInterpolationString(InterpolationString node) {
+    _writeNextCodeLine(node);
+    _writeln('InterpolationString');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('contents', node.contents);
+      _addInterpolationElement(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitIsExpression(IsExpression node) {
+    _writeNextCodeLine(node);
+    _writeln('IsExpression');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('expression', node.expression);
+      properties.addNode('type', node.type);
+      _addExpression(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitLabel(Label node) {
+    _writeNextCodeLine(node);
+    _writeln('Label');
+    _withIndent(() {
+      _writeNode('label', node.label);
+    });
+  }
+
+  @override
+  void visitLibraryDirective(LibraryDirective node) {
+    _writeNextCodeLine(node);
+    _writeln('LibraryDirective');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('name', node.name);
+      _addDirective(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitLibraryIdentifier(LibraryIdentifier node) {
+    _writeNextCodeLine(node);
+    _writeln('LibraryIdentifier');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNodeList('components', node.components);
+      _addIdentifier(properties, node);
+      _writeProperties(properties);
     });
   }
 
   @override
   void visitListLiteral(ListLiteral node) {
+    _writeNextCodeLine(node);
     _writeln('ListLiteral');
     _withIndent(() {
-      _writeNodeList('elements', node.elements);
-      _writeType('staticType', node.staticType);
-      _writeNode('typeArguments', node.typeArguments);
+      var properties = _Properties();
+      properties.addNodeList('elements', node.elements);
+      _addTypedLiteral(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitMapLiteralEntry(MapLiteralEntry node) {
+    _writeNextCodeLine(node);
+    _writeln('SetOrMapLiteral');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('key', node.key);
+      properties.addNode('value', node.value);
+      _addCollectionElement(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitMethodDeclaration(MethodDeclaration node) {
+    _writeNextCodeLine(node);
+    _writeln('MethodDeclaration');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('body', node.body);
+      properties.addType('declaredElementType', node.declaredElement.type);
+      properties.addToken('externalKeyword', node.externalKeyword);
+      properties.addToken('modifierKeyword', node.modifierKeyword);
+      properties.addNode('name', node.name);
+      properties.addToken('operatorKeyword', node.operatorKeyword);
+      properties.addNode('parameters', node.parameters);
+      properties.addToken('propertyKeyword', node.propertyKeyword);
+      properties.addNode('returnType', node.returnType);
+      properties.addNode('typeParameters', node.typeParameters);
+      _addClassMember(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitMethodInvocation(MethodInvocation node) {
+    _writeNextCodeLine(node);
+    _writeln('MethodInvocation');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('methodName', node.methodName);
+      properties.addToken('operator', node.operator);
+      properties.addNode('target', node.target);
+      _addInvocationExpression(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitMixinDeclaration(MixinDeclaration node) {
+    _writeNextCodeLine(node);
+    _writeln('MixinDeclaration');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('mixinKeyword', node.mixinKeyword);
+      properties.addNode('onClause', node.onClause);
+      _addClassOrMixinDeclaration(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitNamedExpression(NamedExpression node) {
+    _writeNextCodeLine(node);
+    _writeln('NamedExpression');
+    _withIndent(() {
+      _writeNode('name', node.name);
+      _writeNode('expression', node.expression);
+    });
+  }
+
+  @override
+  void visitNullLiteral(NullLiteral node) {
+    _writeNextCodeLine(node);
+    _writeln('NullLiteral');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('literal', node.literal);
+      _addLiteral(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitOnClause(OnClause node) {
+    _writeNextCodeLine(node);
+    _writeln('OnClause');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('onKeyword', node.onKeyword);
+      properties.addNodeList(
+          'superclassConstraints', node.superclassConstraints);
+      _addAstNode(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitParenthesizedExpression(ParenthesizedExpression node) {
+    _writeNextCodeLine(node);
+    _writeln('ParenthesizedExpression');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('expression', node.expression);
+      _addExpression(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitPartDirective(PartDirective node) {
+    _writeNextCodeLine(node);
+    _writeln('PartDirective');
+    _withIndent(() {
+      var properties = _Properties();
+      _addUriBasedDirective(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitPartOfDirective(PartOfDirective node) {
+    _writeNextCodeLine(node);
+    _writeln('PartOfDirective');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('libraryName', node.libraryName);
+      properties.addToken('ofKeyword', node.ofKeyword);
+      properties.addToken('partKeyword', node.partKeyword);
+      properties.addToken('semicolon', node.semicolon);
+      _addDirective(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitPostfixExpression(PostfixExpression node) {
+    _writeNextCodeLine(node);
+    _writeln('PostfixExpression');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('operand', node.operand);
+      properties.addToken('operator', node.operator);
+      _addExpression(properties, node);
+      _addMethodReferenceExpression(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitPrefixedIdentifier(PrefixedIdentifier node) {
+    _writeNextCodeLine(node);
+    _writeln('PrefixedIdentifier');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('identifier', node.identifier);
+      properties.addToken('period', node.period);
+      properties.addNode('prefix', node.prefix);
+      _addIdentifier(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitPrefixExpression(PrefixExpression node) {
+    _writeNextCodeLine(node);
+    _writeln('PrefixExpression');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('operand', node.operand);
+      properties.addToken('operator', node.operator);
+      _addExpression(properties, node);
+      _addMethodReferenceExpression(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitPropertyAccess(PropertyAccess node) {
+    _writeNextCodeLine(node);
+    _writeln('PropertyAccess');
+    _withIndent(() {
+      var properties = _Properties();
+      _writeToken('operator', node.operator);
+      properties.addNode('propertyName', node.propertyName);
+      properties.addNode('target', node.target);
+      _addExpression(properties, node);
+      _writeProperties(properties);
     });
   }
 
@@ -92,6 +1083,7 @@
   void visitRedirectingConstructorInvocation(
     RedirectingConstructorInvocation node,
   ) {
+    _writeNextCodeLine(node);
     _writeln('RedirectingConstructorInvocation');
     _withIndent(() {
       _writeNode('argumentList', node.argumentList);
@@ -101,18 +1093,93 @@
   }
 
   @override
+  void visitReturnStatement(ReturnStatement node) {
+    _writeNextCodeLine(node);
+    _writeln('ReturnStatement');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('expression', node.expression);
+      properties.addToken('returnKeyword', node.returnKeyword);
+      properties.addToken('semicolon', node.semicolon);
+      _addStatement(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitSetOrMapLiteral(SetOrMapLiteral node) {
+    _writeNextCodeLine(node);
+    _writeln('SetOrMapLiteral');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNodeList('elements', node.elements);
+      properties.addRaw('isMap', node.isMap);
+      _addTypedLiteral(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitShowCombinator(ShowCombinator node) {
+    _writeNextCodeLine(node);
+    _writeln('ShowCombinator');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNodeList('shownNames', node.shownNames);
+      _addCombinator(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitSimpleFormalParameter(SimpleFormalParameter node) {
+    _writeNextCodeLine(node);
+    _writeln('SimpleFormalParameter');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('keyword', node.keyword);
+      properties.addNode('type', node.type);
+      _addNormalFormalParameter(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
   void visitSimpleIdentifier(SimpleIdentifier node) {
+    _writeNextCodeLine(node);
     _writeln('SimpleIdentifier');
     _withIndent(() {
       _writeAuxiliaryElements('auxiliaryElements', node.auxiliaryElements);
       _writeElement('staticElement', node.staticElement);
       _writeType('staticType', node.staticType);
-      _writelnWithIndent('token: ${node.token}');
+      _writeToken('token', node.token);
+    });
+  }
+
+  @override
+  void visitSimpleStringLiteral(SimpleStringLiteral node) {
+    _writeNextCodeLine(node);
+    _writeln('SimpleStringLiteral');
+    _withIndent(() {
+      _writeToken('literal', node.literal);
+    });
+  }
+
+  @override
+  void visitStringInterpolation(StringInterpolation node) {
+    _writeNextCodeLine(node);
+    _writeln('StringInterpolation');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNodeList('elements', node.elements);
+      _addSingleStringLiteral(properties, node);
+      _writeProperties(properties);
     });
   }
 
   @override
   void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
+    _writeNextCodeLine(node);
     _writeln('SuperConstructorInvocation');
     _withIndent(() {
       _writeNode('argumentList', node.argumentList);
@@ -122,7 +1189,119 @@
   }
 
   @override
+  void visitSuperExpression(SuperExpression node) {
+    _writeNextCodeLine(node);
+    _writeln('SuperExpression');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('superKeyword', node.superKeyword);
+      _addExpression(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitSwitchCase(SwitchCase node) {
+    _writeNextCodeLine(node);
+    _writeln('SwitchCase');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('expression', node.expression);
+      _addSwitchMember(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitSwitchDefault(SwitchDefault node) {
+    _writeNextCodeLine(node);
+    _writeln('SwitchDefault');
+    _withIndent(() {
+      var properties = _Properties();
+      _addSwitchMember(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitSwitchStatement(SwitchStatement node) {
+    _writeNextCodeLine(node);
+    _writeln('SwitchStatement');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('expression', node.expression);
+      properties.addNodeList('members', node.members);
+      _addStatement(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitThisExpression(ThisExpression node) {
+    _writeNextCodeLine(node);
+    _writeln('ThisExpression');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('thisKeyword', node.thisKeyword);
+      _addExpression(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitThrowExpression(ThrowExpression node) {
+    _writeNextCodeLine(node);
+    _writeln('ThrowExpression');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('expression', node.expression);
+      _addExpression(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
+    _writeNextCodeLine(node);
+    _writeln('TopLevelVariableDeclaration');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('semicolon', node.semicolon);
+      properties.addNode('variables', node.variables);
+      _addCompilationUnitMember(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitTryStatement(TryStatement node) {
+    _writeNextCodeLine(node);
+    _writeln('TryStatement');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('body', node.body);
+      properties.addNodeList('catchClauses', node.catchClauses);
+      properties.addNode('finallyBlock', node.finallyBlock);
+      _addStatement(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitTypeArgumentList(TypeArgumentList node) {
+    _writeNextCodeLine(node);
+    _writeln('TypeArgumentList');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNodeList('arguments', node.arguments);
+      _addAstNode(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
   void visitTypeName(TypeName node) {
+    _writeNextCodeLine(node);
     _writeln('TypeName');
     _withIndent(() {
       _writeNode('name', node.name);
@@ -131,19 +1310,351 @@
     });
   }
 
+  @override
+  void visitTypeParameter(TypeParameter node) {
+    _writeNextCodeLine(node);
+    _writeln('TypeParameter');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('bound', node.bound);
+      properties.addNode('name', node.name);
+      _addDeclaration(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitTypeParameterList(TypeParameterList node) {
+    _writeNextCodeLine(node);
+    _writeln('TypeParameterList');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNodeList('typeParameters', node.typeParameters);
+      _addAstNode(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitVariableDeclaration(VariableDeclaration node) {
+    _writeNextCodeLine(node);
+    _writeln('VariableDeclaration');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('initializer', node.initializer);
+      properties.addNode('name', node.name);
+      _addDeclaration(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitVariableDeclarationList(VariableDeclarationList node) {
+    _writeNextCodeLine(node);
+    _writeln('VariableDeclarationList');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('keyword', node.keyword);
+      properties.addToken('lateKeyword', node.lateKeyword);
+      properties.addNode('type', node.type);
+      properties.addNodeList('variables', node.variables);
+      _addAnnotatedNode(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitVariableDeclarationStatement(VariableDeclarationStatement node) {
+    _writeNextCodeLine(node);
+    _writeln('VariableDeclarationStatement');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('semicolon', node.semicolon);
+      properties.addNode('variables', node.variables);
+      _addStatement(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitWhileStatement(WhileStatement node) {
+    _writeNextCodeLine(node);
+    _writeln('WhileStatement');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('body', node.body);
+      properties.addNode('condition', node.condition);
+      _addStatement(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitWithClause(WithClause node) {
+    _writeNextCodeLine(node);
+    _writeln('WithClause');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addToken('withKeyword', node.withKeyword);
+      properties.addNodeList('mixinTypes', node.mixinTypes);
+      _addAstNode(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  @override
+  void visitYieldStatement(YieldStatement node) {
+    _writeNextCodeLine(node);
+    _writeln('YieldStatement');
+    _withIndent(() {
+      var properties = _Properties();
+      properties.addNode('expression', node.expression);
+      properties.addToken('star', node.star);
+      properties.addToken('yieldKeyword', node.yieldKeyword);
+      _addStatement(properties, node);
+      _writeProperties(properties);
+    });
+  }
+
+  void _addAnnotatedNode(_Properties properties, AnnotatedNode node) {
+    properties.addNode('documentationComment', node.documentationComment);
+    properties.addNodeList('metadata', node.metadata);
+    _addAstNode(properties, node);
+  }
+
+  void _addAssertion(_Properties properties, Assertion node) {
+    properties.addNode('condition', node.condition);
+    properties.addNode('message', node.message);
+    _addAstNode(properties, node);
+  }
+
+  void _addAstNode(_Properties properties, AstNode node) {}
+
+  void _addClassMember(_Properties properties, ClassMember node) {
+    _addDeclaration(properties, node);
+  }
+
+  void _addClassOrMixinDeclaration(
+    _Properties properties,
+    ClassOrMixinDeclaration node,
+  ) {
+    properties.addNode('implementsClause', node.implementsClause);
+    properties.addNodeList('members', node.members);
+    properties.addNode('typeParameters', node.typeParameters);
+    _addNamedCompilationUnitMember(properties, node);
+  }
+
+  void _addCollectionElement(_Properties properties, CollectionElement node) {
+    _addAstNode(properties, node);
+  }
+
+  void _addCombinator(_Properties properties, Combinator node) {
+    properties.addToken('keyword', node.keyword);
+    _addAstNode(properties, node);
+  }
+
+  void _addCompilationUnitMember(
+    _Properties properties,
+    CompilationUnitMember node,
+  ) {
+    _addDeclaration(properties, node);
+  }
+
+  void _addConstructorInitializer(
+    _Properties properties,
+    ConstructorInitializer node,
+  ) {
+    _addAstNode(properties, node);
+  }
+
+  void _addConstructorReferenceNode(
+    _Properties properties,
+    ConstructorReferenceNode node,
+  ) {
+    properties.addElement('staticElement', node.staticElement);
+    _addAstNode(properties, node);
+  }
+
+  void _addDeclaration(_Properties properties, Declaration node) {
+    properties.addElement('declaredElement', node.declaredElement);
+    _addAnnotatedNode(properties, node);
+  }
+
+  void _addDirective(
+    _Properties properties,
+    Directive node,
+  ) {
+    properties.addElement('element', node.element);
+    _addAnnotatedNode(properties, node);
+  }
+
+  void _addExpression(_Properties properties, Expression node) {
+    properties.addType('staticType', node.staticType);
+    _addAstNode(properties, node);
+  }
+
+  void _addForEachParts(_Properties properties, ForEachParts node) {
+    properties.addToken('inKeyword', node.inKeyword);
+    properties.addNode('iterable', node.iterable);
+    _addForLoopParts(properties, node);
+  }
+
+  void _addForLoopParts(_Properties properties, ForLoopParts node) {
+    _addAstNode(properties, node);
+  }
+
+  void _addFormalParameter(_Properties properties, FormalParameter node) {
+    properties.addToken('covariantKeyword', node.covariantKeyword);
+    properties.addElement('declaredElement', node.declaredElement);
+    properties.addType('declaredElementType', node.declaredElement.type);
+    properties.addNode('identifier', node.identifier);
+    properties.addNodeList('metadata', node.metadata);
+    properties.addToken('requiredKeyword', node.requiredKeyword);
+    _addAstNode(properties, node);
+  }
+
+  void _addForParts(_Properties properties, ForParts node) {
+    properties.addNode('condition', node.condition);
+    properties.addNodeList('updaters', node.updaters);
+    _addForLoopParts(properties, node);
+  }
+
+  void _addFunctionBody(_Properties properties, FunctionBody node) {
+    properties.addToken('keyword', node.keyword);
+    properties.addToken('star', node.star);
+    _addAstNode(properties, node);
+  }
+
+  void _addIdentifier(
+    _Properties properties,
+    Identifier node,
+  ) {
+    properties.addElement('staticElement', node.staticElement);
+    _addExpression(properties, node);
+  }
+
+  void _addInterpolationElement(
+    _Properties properties,
+    InterpolationElement node,
+  ) {
+    _addAstNode(properties, node);
+  }
+
+  void _addInvocationExpression(
+    _Properties properties,
+    InvocationExpression node,
+  ) {
+    properties.addNode('argumentList', node.argumentList);
+    properties.addType('staticInvokeType', node.staticInvokeType);
+    properties.addNode('typeArguments', node.typeArguments);
+    properties.addTypeList('typeArgumentTypes', node.typeArgumentTypes);
+    _addExpression(properties, node);
+  }
+
+  void _addLiteral(_Properties properties, Literal node) {
+    _addExpression(properties, node);
+  }
+
+  void _addMethodReferenceExpression(
+    _Properties properties,
+    MethodReferenceExpression node,
+  ) {
+    properties.addElement('staticElement', node.staticElement);
+    _addAstNode(properties, node);
+  }
+
+  void _addNamedCompilationUnitMember(
+    _Properties properties,
+    NamedCompilationUnitMember node,
+  ) {
+    properties.addNode('name', node.name);
+    _addCompilationUnitMember(properties, node);
+  }
+
+  void _addNamespaceDirective(
+    _Properties properties,
+    NamespaceDirective node,
+  ) {
+    properties.addNodeList('combinators', node.combinators);
+    properties.addNodeList('configurations', node.configurations);
+    properties.addSource('selectedSource', node.selectedSource);
+    properties.addRaw('selectedUriContent', node.selectedUriContent);
+    _addUriBasedDirective(properties, node);
+  }
+
+  void _addNormalFormalParameter(
+    _Properties properties,
+    NormalFormalParameter node,
+  ) {
+    properties.addNode('documentationComment', node.documentationComment);
+    _addFormalParameter(properties, node);
+  }
+
+  void _addSingleStringLiteral(
+      _Properties properties, SingleStringLiteral node) {
+    _addStringLiteral(properties, node);
+  }
+
+  void _addStatement(_Properties properties, Statement node) {
+    _addAstNode(properties, node);
+  }
+
+  void _addStringLiteral(_Properties properties, StringLiteral node) {
+    properties.addRaw('stringValue', node.stringValue);
+    _addLiteral(properties, node);
+  }
+
+  void _addSwitchMember(_Properties properties, SwitchMember node) {
+    properties.addToken('keyword', node.keyword);
+    properties.addNodeList('labels', node.labels);
+    properties.addNodeList('statements', node.statements);
+    _addAstNode(properties, node);
+  }
+
+  void _addTypeAlias(_Properties properties, TypeAlias node) {
+    properties.addToken('semicolon', node.semicolon);
+    properties.addToken('typedefKeyword', node.typedefKeyword);
+    _addNamedCompilationUnitMember(properties, node);
+  }
+
+  void _addTypeAnnotation(_Properties properties, TypeAnnotation node) {
+    properties.addToken('question', node.question);
+    properties.addType('type', node.type);
+    _addAstNode(properties, node);
+  }
+
+  void _addTypedLiteral(_Properties properties, TypedLiteral node) {
+    properties.addToken('constKeyword', node.constKeyword);
+    properties.addNode('typeArguments', node.typeArguments);
+    _addLiteral(properties, node);
+  }
+
+  void _addUriBasedDirective(
+    _Properties properties,
+    UriBasedDirective node,
+  ) {
+    properties.addNode('uri', node.uri);
+    properties.addRaw('uriContent', node.uriContent);
+    properties.addElement('uriElement', node.uriElement);
+    properties.addSource('uriSource', node.uriSource);
+    _addDirective(properties, node);
+  }
+
   String _referenceToString(Reference reference) {
-    if (reference.parent.name == '@unit') {
-      var libraryUriStr = reference.parent.parent.name;
+    if (reference.parent.parent == null) {
+      var libraryUriStr = reference.name;
       if (libraryUriStr == _selfUriStr) {
         return 'self';
       }
       return libraryUriStr;
     }
 
-    var name = reference.name;
-    if (name.startsWith('@')) {
-      return _referenceToString(reference.parent);
+    // Ignore the unit, skip to the library.
+    if (reference.parent.name == '@unit') {
+      return _referenceToString(reference.parent.parent);
     }
+
+    var name = reference.name;
     if (name.isEmpty) {
       name = '•';
     }
@@ -159,15 +1670,22 @@
 
   void _writeAuxiliaryElements(String name, AuxiliaryElements elements) {
     if (elements != null) {
-      throw UnimplementedError();
+      _sink.write(_indent);
+      _sink.write('$name: ');
+      _writeElement0(elements.staticElement);
     }
   }
 
   void _writeElement(String name, Element element) {
     _sink.write(_indent);
     _sink.write('$name: ');
+    _writeElement0(element);
+  }
+
+  void _writeElement0(Element element) {
     if (element == null) {
       _sink.writeln('<null>');
+      return;
     } else if (element is Member) {
       _sink.writeln(_nameOfMemberClass(element));
       _withIndent(() {
@@ -176,8 +1694,12 @@
       });
     } else {
       var reference = (element as ElementImpl).reference;
-      var referenceStr = _referenceToString(reference);
-      _sink.writeln(referenceStr);
+      if (reference != null) {
+        var referenceStr = _referenceToString(reference);
+        _sink.writeln(referenceStr);
+      } else {
+        _sink.writeln('${element.name}@${element.nameOffset}');
+      }
     }
   }
 
@@ -190,6 +1712,15 @@
     _sink.writeln(line);
   }
 
+  void _writeNextCodeLine(AstNode node) {
+    var nextCodeLine = _codeLinesProvider?.nextLine(node.offset);
+    if (nextCodeLine != null) {
+      nextCodeLine = nextCodeLine.trim();
+      _sink.writeln('// $nextCodeLine');
+      _sink.write(_indent);
+    }
+  }
+
   void _writeNode(String name, AstNode node) {
     if (node != null) {
       _sink.write(_indent);
@@ -210,11 +1741,211 @@
     }
   }
 
+  void _writeProperties(_Properties container) {
+    var properties = container.properties;
+    properties.sort((a, b) => a.name.compareTo(b.name));
+    for (var property in properties) {
+      property.write(this);
+    }
+  }
+
+  void _writeSource(String name, Source source) {
+    if (source != null) {
+      _writelnWithIndent('$name: ${source.uri}');
+    } else {
+      _writelnWithIndent('$name: <null>');
+    }
+  }
+
+  void _writeToken(String name, Token token) {
+    if (token != null) {
+      _sink.write(_indent);
+      _sink.writeln('$name: $token');
+    }
+  }
+
   void _writeType(String name, DartType type) {
     _writelnWithIndent('$name: $type');
   }
 
+  void _writeTypeList(String name, List<DartType> types) {
+    if (types.isNotEmpty) {
+      _writelnWithIndent(name);
+      _withIndent(() {
+        for (var type in types) {
+          _sink.write(_indent);
+          _sink.writeln('$type');
+        }
+      });
+    }
+  }
+
   static String _nameOfMemberClass(Member member) {
     return '${member.runtimeType}';
   }
 }
+
+class _AuxiliaryElementsProperty extends _Property {
+  final AuxiliaryElements elements;
+
+  _AuxiliaryElementsProperty(String name, this.elements) : super(name);
+
+  @override
+  void write(ResolvedAstPrinter printer) {
+    printer._writeAuxiliaryElements(name, elements);
+  }
+}
+
+class _ElementProperty extends _Property {
+  final Element element;
+
+  _ElementProperty(String name, this.element) : super(name);
+
+  @override
+  void write(ResolvedAstPrinter printer) {
+    printer._writeElement(name, element);
+  }
+}
+
+class _NodeListProperty extends _Property {
+  final NodeList nodeList;
+
+  _NodeListProperty(String name, this.nodeList) : super(name);
+
+  @override
+  void write(ResolvedAstPrinter printer) {
+    printer._writeNodeList(name, nodeList);
+  }
+}
+
+class _NodeProperty extends _Property {
+  final AstNode node;
+
+  _NodeProperty(String name, this.node) : super(name);
+
+  @override
+  void write(ResolvedAstPrinter printer) {
+    printer._writeNode(name, node);
+  }
+}
+
+class _Properties {
+  final properties = <_Property>[];
+
+  void addAuxiliaryElements(String name, AuxiliaryElements elements) {
+    properties.add(
+      _AuxiliaryElementsProperty(name, elements),
+    );
+  }
+
+  void addElement(String name, Element element) {
+    properties.add(
+      _ElementProperty(name, element),
+    );
+  }
+
+  void addNode(String name, AstNode node) {
+    properties.add(
+      _NodeProperty(name, node),
+    );
+  }
+
+  void addNodeList(String name, NodeList nodeList) {
+    properties.add(
+      _NodeListProperty(name, nodeList),
+    );
+  }
+
+  void addRaw(String name, Object value) {
+    properties.add(
+      _RawProperty(name, value),
+    );
+  }
+
+  void addSource(String name, Source source) {
+    properties.add(
+      _SourceProperty(name, source),
+    );
+  }
+
+  void addToken(String name, Token token) {
+    properties.add(
+      _TokenProperty(name, token),
+    );
+  }
+
+  void addType(String name, DartType type) {
+    properties.add(
+      _TypeProperty(name, type),
+    );
+  }
+
+  void addTypeList(String name, List<DartType> types) {
+    properties.add(
+      _TypeListProperty(name, types),
+    );
+  }
+}
+
+abstract class _Property {
+  final String name;
+
+  _Property(this.name);
+
+  void write(ResolvedAstPrinter printer);
+}
+
+class _RawProperty extends _Property {
+  final Object value;
+
+  _RawProperty(String name, this.value) : super(name);
+
+  @override
+  void write(ResolvedAstPrinter printer) {
+    printer._writelnWithIndent('$name: $value');
+  }
+}
+
+class _SourceProperty extends _Property {
+  final Source source;
+
+  _SourceProperty(String name, this.source) : super(name);
+
+  @override
+  void write(ResolvedAstPrinter printer) {
+    printer._writeSource(name, source);
+  }
+}
+
+class _TokenProperty extends _Property {
+  final Token token;
+
+  _TokenProperty(String name, this.token) : super(name);
+
+  @override
+  void write(ResolvedAstPrinter printer) {
+    printer._writeToken(name, token);
+  }
+}
+
+class _TypeListProperty extends _Property {
+  final List<DartType> types;
+
+  _TypeListProperty(String name, this.types) : super(name);
+
+  @override
+  void write(ResolvedAstPrinter printer) {
+    printer._writeTypeList(name, types);
+  }
+}
+
+class _TypeProperty extends _Property {
+  final DartType type;
+
+  _TypeProperty(String name, this.type) : super(name);
+
+  @override
+  void write(ResolvedAstPrinter printer) {
+    printer._writeType(name, type);
+  }
+}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 39cd771..223e3b7 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -4308,8 +4308,9 @@
         argumentList: ArgumentList
           arguments
             ListLiteral
+              constKeyword: const
               staticType: List<String>
-        staticElement: self::A::•
+        staticElement: self::@class::A::@constructor::•
 }
 ''',
         withFullyResolvedAst: true);
@@ -4413,8 +4414,9 @@
         argumentList: ArgumentList
           arguments
             ListLiteral
+              constKeyword: const
               staticType: List<String>
-        staticElement: self::A::•
+        staticElement: self::@class::A::@constructor::•
 }
 ''',
         withFullyResolvedAst: true);
@@ -6115,6 +6117,7 @@
   final List<int> f1;
     constantInitializer
       ListLiteral
+        constKeyword: const
         staticType: List<int>
   const C1();
 }
@@ -8128,17 +8131,17 @@
   void bar() {}
     metadata
       Annotation
-        element: self::C::foo
+        element: self::@class::C::@getter::foo
         name: SimpleIdentifier
-          staticElement: self::C::foo
+          staticElement: self::@class::C::@getter::foo
           staticType: int
           token: foo
 }
   metadata
     Annotation
-      element: self::foo
+      element: self::@getter::foo
       name: SimpleIdentifier
-        staticElement: self::foo
+        staticElement: self::@getter::foo
         staticType: int
         token: foo
   typeParameters
@@ -8147,9 +8150,9 @@
       defaultType: dynamic
       metadata
         Annotation
-          element: self::foo
+          element: self::@getter::foo
           name: SimpleIdentifier
-            staticElement: self::foo
+            staticElement: self::@getter::foo
             staticType: int
             token: foo
 const int foo;
@@ -8366,17 +8369,17 @@
   void bar() {}
     metadata
       Annotation
-        element: self::E::foo
+        element: self::@extension::E::@getter::foo
         name: SimpleIdentifier
-          staticElement: self::E::foo
+          staticElement: self::@extension::E::@getter::foo
           staticType: int
           token: foo
 }
   metadata
     Annotation
-      element: self::foo
+      element: self::@getter::foo
       name: SimpleIdentifier
-        staticElement: self::foo
+        staticElement: self::@getter::foo
         staticType: int
         token: foo
   typeParameters
@@ -8385,9 +8388,9 @@
       defaultType: null
       metadata
         Annotation
-          element: self::foo
+          element: self::@getter::foo
           name: SimpleIdentifier
-            staticElement: self::foo
+            staticElement: self::@getter::foo
             staticType: int
             token: foo
 const int foo;
@@ -8676,17 +8679,17 @@
   void bar() {}
     metadata
       Annotation
-        element: self::M::foo
+        element: self::@mixin::M::@getter::foo
         name: SimpleIdentifier
-          staticElement: self::M::foo
+          staticElement: self::@mixin::M::@getter::foo
           staticType: int
           token: foo
 }
   metadata
     Annotation
-      element: self::foo
+      element: self::@getter::foo
       name: SimpleIdentifier
-        staticElement: self::foo
+        staticElement: self::@getter::foo
         staticType: int
         token: foo
   typeParameters
@@ -8695,9 +8698,9 @@
       defaultType: dynamic
       metadata
         Annotation
-          element: self::foo
+          element: self::@getter::foo
           name: SimpleIdentifier
-            staticElement: self::foo
+            staticElement: self::@getter::foo
             staticType: int
             token: foo
 const int foo;
@@ -11250,12 +11253,12 @@
       constructorName: ConstructorName
         type: TypeName
           name: SimpleIdentifier
-            staticElement: self::A
+            staticElement: self::@class::A
             staticType: A<dynamic>
             token: A
           type: A<int>
       staticElement: ConstructorMember
-        base: self::A::•
+        base: self::@class::A::@constructor::•
         substitution: {T: int}
       staticType: A<int>
 ''',
diff --git a/pkg/analyzer/test/src/task/strong/dart2_inference_test.dart b/pkg/analyzer/test/src/task/strong/dart2_inference_test.dart
index 275c530..5a7066d 100644
--- a/pkg/analyzer/test/src/task/strong/dart2_inference_test.dart
+++ b/pkg/analyzer/test/src/task/strong/dart2_inference_test.dart
@@ -620,7 +620,9 @@
     void assertTypes(
         String vSearch, String vType, String fSearch, String fType) {
       var node = findNode.simple(vSearch);
-      expect(node.staticType.toString(), vType);
+
+      var element = node.staticElement as LocalVariableElement;
+      expect(element.type.toString(), vType);
 
       var invocation = findNode.methodInvocation(fSearch);
       expect(invocation.staticType.toString(), fType);
@@ -692,11 +694,13 @@
 var y = {};
 ''';
     await resolveTestCode(code);
-    SimpleIdentifier x = findNode.expression('x = ');
-    expect(x.staticType.toString(), 'List<dynamic>');
+    var xNode = findNode.simple('x = ');
+    var xElement = xNode.staticElement as VariableElement;
+    expect(xElement.type.toString(), 'List<dynamic>');
 
-    SimpleIdentifier y = findNode.expression('y = ');
-    expect(y.staticType.toString(), 'Map<dynamic, dynamic>');
+    var yNode = findNode.simple('y = ');
+    var yElement = yNode.staticElement as VariableElement;
+    expect(yElement.type.toString(), 'Map<dynamic, dynamic>');
   }
 
   test_listMap_null() async {
@@ -705,11 +709,13 @@
 var y = {null: null};
 ''';
     await resolveTestCode(code);
-    SimpleIdentifier x = findNode.expression('x = ');
-    expect(x.staticType.toString(), 'List<Null>');
+    var xNode = findNode.simple('x = ');
+    var xElement = xNode.staticElement as VariableElement;
+    expect(xElement.type.toString(), 'List<Null>');
 
-    SimpleIdentifier y = findNode.expression('y = ');
-    expect(y.staticType.toString(), 'Map<Null, Null>');
+    var yNode = findNode.simple('y = ');
+    var yElement = yNode.staticElement as VariableElement;
+    expect(yElement.type.toString(), 'Map<Null, Null>');
   }
 
   test_switchExpression_asContext_forCases() async {
@@ -742,11 +748,13 @@
 }
 ''';
     await resolveTestCode(code);
-    SimpleIdentifier x = findNode.expression('x = ');
-    expect(x.staticType, VoidTypeImpl.instance);
+    var xNode = findNode.simple('x = ');
+    var xElement = xNode.staticElement as VariableElement;
+    expect(xElement.type, VoidTypeImpl.instance);
 
-    SimpleIdentifier y = findNode.expression('y = ');
-    expect(y.staticType, VoidTypeImpl.instance);
+    var yNode = findNode.simple('y = ');
+    var yElement = yNode.staticElement as VariableElement;
+    expect(yElement.type, VoidTypeImpl.instance);
   }
 
   test_voidType_topLevelFunction() async {
@@ -758,11 +766,13 @@
 }
 ''';
     await resolveTestCode(code);
-    SimpleIdentifier x = findNode.expression('x = ');
-    expect(x.staticType, VoidTypeImpl.instance);
+    var xNode = findNode.simple('x = ');
+    var xElement = xNode.staticElement as VariableElement;
+    expect(xElement.type, VoidTypeImpl.instance);
 
-    SimpleIdentifier y = findNode.expression('y = ');
-    expect(y.staticType, VoidTypeImpl.instance);
+    var yNode = findNode.simple('y = ');
+    var yElement = yNode.staticElement as VariableElement;
+    expect(yElement.type, VoidTypeImpl.instance);
   }
 
   void _assertTypeAnnotations() {
@@ -792,7 +802,8 @@
         if (comment != null) {
           String expectedType = types[comment.offset];
           if (expectedType != null) {
-            String actualType = node.staticType.toString();
+            VariableElement element = node.staticElement;
+            String actualType = element.type.toString();
             expect(actualType, expectedType, reason: '@${comment.offset}');
           }
         }
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index 36d5eb0..ce2d4c7 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -366,7 +366,7 @@
 ''');
     var v = mainUnit.topLevelVariables[0];
     expect(v.type.toString(), 'dynamic');
-    expect(v.initializer.type.toString(), 'dynamic Function()');
+    expect(v.initializer.type.toString(), 'Null Function()');
   }
 
   test_bottom_inClosure() async {
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
index 8757439..2fafd4d 100644
--- a/pkg/analyzer/tool/diagnostics/diagnostics.md
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -1307,7 +1307,7 @@
 
 ### invalid_use_of_covariant_in_extension
 
-_The 'covariant' keyword can't be used in an extension._
+_Can't have modifier '#lexeme' in an extension._
 
 #### Description
 
@@ -2216,7 +2216,7 @@
 
 ### sdk_version_ui_as_code
 
-_The for, if, and spread elements weren't supported until version 2.2.2, but
+_The for, if, and spread elements weren't supported until version 2.3.0, but
 this code is required to be able to run on earlier versions._
 
 #### Description
diff --git a/pkg/analyzer_plugin/CHANGELOG.md b/pkg/analyzer_plugin/CHANGELOG.md
index 8c46bac..6172dd2 100644
--- a/pkg/analyzer_plugin/CHANGELOG.md
+++ b/pkg/analyzer_plugin/CHANGELOG.md
@@ -1,4 +1,8 @@
-## 0.2.0 (Not yet published)
+## 0.2.1
+- Bump maximum supported version of the analyzer to `<0.39.0`.
+- Bug fixes: #37916, #38326.
+
+## 0.2.0
 - Change `DartEditBuilder.writeOverride()` to accept `ExecutableElement`
   instead of `FunctionType`.
 
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 eb6ee1c..cf31db3 100644
--- a/pkg/analyzer_plugin/lib/utilities/completion/type_member_contributor.dart
+++ b/pkg/analyzer_plugin/lib/utilities/completion/type_member_contributor.dart
@@ -265,7 +265,8 @@
   @override
   void declaredLocalVar(SimpleIdentifier name, TypeAnnotation type) {
     if (name.name == targetName) {
-      typeFound = name.staticType;
+      var element = name.staticElement as VariableElement;
+      typeFound = element.type;
       finished();
     }
   }
diff --git a/pkg/analyzer_plugin/pubspec.yaml b/pkg/analyzer_plugin/pubspec.yaml
index 0fe28a95..59ee846 100644
--- a/pkg/analyzer_plugin/pubspec.yaml
+++ b/pkg/analyzer_plugin/pubspec.yaml
@@ -1,6 +1,6 @@
 name: analyzer_plugin
 description: A framework and support code for building plugins for the analysis server.
-version: 0.2.0
+version: 0.2.1
 author: Dart Team <misc@dartlang.org>
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer_plugin
 
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index 7113669..e302fd1 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -18,7 +18,9 @@
 import '../js/js.dart' as js;
 import '../js_backend/backend.dart';
 import '../js_backend/namer.dart';
+import '../js_backend/type_reference.dart' show TypeReference;
 import '../js_emitter/code_emitter_task.dart' show Emitter;
+import '../js_model/type_recipe.dart' show TypeRecipe;
 import '../native/behavior.dart';
 import '../serialization/serialization.dart';
 import '../ssa/ssa.dart';
@@ -1023,6 +1025,7 @@
   expressionStatement,
   block,
   program,
+  typeReference,
 }
 
 /// Tags used for debugging serialization/deserialization boundary mismatches.
@@ -1085,6 +1088,7 @@
   static const String expressionStatement = 'js-expressionStatement';
   static const String block = 'js-block';
   static const String program = 'js-program';
+  static const String typeReference = 'js-typeReference';
 }
 
 /// Visitor that serializes a [js.Node] into a [DataSink].
@@ -1321,6 +1325,12 @@
       node.writeToDataSink(sink);
       sink.end(JsNodeTags.modularExpression);
       _writeInfo(node);
+    } else if (node is TypeReference) {
+      sink.writeEnum(JsNodeKind.typeReference);
+      sink.begin(JsNodeTags.typeReference);
+      node.writeToDataSink(sink);
+      sink.end(JsNodeTags.typeReference);
+      _writeInfo(node);
     } else {
       throw new UnsupportedError(
           'Unexpected deferred expression: ${node.runtimeType}.');
@@ -2112,6 +2122,11 @@
         node = new js.Program(body);
         source.end(JsNodeTags.program);
         break;
+      case JsNodeKind.typeReference:
+        source.begin(JsNodeTags.typeReference);
+        node = TypeReference.readFromDataSource(source);
+        source.end(JsNodeTags.typeReference);
+        break;
     }
     SourceInformation sourceInformation =
         source.readCached<SourceInformation>(() {
@@ -2152,6 +2167,11 @@
   OutputUnit readOutputUnitReference(DataSource source) {
     return closedWorld.outputUnitData.outputUnits[source.readInt()];
   }
+
+  @override
+  TypeRecipe readTypeRecipe(DataSource source) {
+    return TypeRecipe.readFromDataSource(source);
+  }
 }
 
 class CodegenWriterImpl implements CodegenWriter {
@@ -2173,4 +2193,9 @@
   void writeOutputUnitReference(DataSink sink, OutputUnit value) {
     sink.writeInt(closedWorld.outputUnitData.outputUnits.indexOf(value));
   }
+
+  @override
+  void writeTypeRecipe(DataSink sink, TypeRecipe recipe) {
+    recipe.writeToDataSink(sink);
+  }
 }
diff --git a/pkg/compiler/lib/src/ir/constants.dart b/pkg/compiler/lib/src/ir/constants.dart
index 958c1ce..5235031 100644
--- a/pkg/compiler/lib/src/ir/constants.dart
+++ b/pkg/compiler/lib/src/ir/constants.dart
@@ -20,13 +20,15 @@
   Dart2jsConstantEvaluator(
       ir.TypeEnvironment typeEnvironment, ReportErrorFunction reportError,
       {Map<String, String> environment: const {},
+      bool enableTripleShift = false,
       bool supportReevaluationForTesting: false})
       : _supportReevaluationForTesting = supportReevaluationForTesting,
         super(
             const Dart2jsConstantsBackend(supportsUnevaluatedConstants: false),
             environment,
             typeEnvironment,
-            new ErrorReporter(reportError));
+            new ErrorReporter(reportError),
+            enableTripleShift: enableTripleShift);
 
   @override
   ErrorReporter get errorReporter => super.errorReporter;
diff --git a/pkg/compiler/lib/src/js_backend/constant_emitter.dart b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
index b7dfa1a..e4b431f 100644
--- a/pkg/compiler/lib/src/js_backend/constant_emitter.dart
+++ b/pkg/compiler/lib/src/js_backend/constant_emitter.dart
@@ -12,6 +12,7 @@
 import '../js/js.dart' as jsAst;
 import '../js/js.dart' show js;
 import '../js_backend/field_analysis.dart';
+import '../js_backend/type_reference.dart' show TypeReference;
 import '../js_emitter/code_emitter_task.dart';
 import '../js_model/type_recipe.dart' show TypeExpressionRecipe;
 import '../options.dart';
@@ -503,9 +504,7 @@
   jsAst.Expression _reifiedTypeNewRti(DartType type) {
     assert(_options.experimentNewRti);
     assert(!type.containsTypeVariables);
-    jsAst.Expression recipe = _rtiRecipeEncoder.encodeGroundRecipe(
-        _emitter, TypeExpressionRecipe(type));
-    return js(r'#(#)', [getHelperProperty(_commonElements.findType), recipe]);
+    return TypeReference(TypeExpressionRecipe(type))..forConstant = true;
   }
 
   @override
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 bdecdbc..62ae8ed 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
@@ -39,7 +39,7 @@
   /// Return the recipe with type variables replaced with <any>. This is a hack
   /// until DartType contains <any> and the parameter stub emitter is replaced
   /// with an SSA path.
-  // TODO(33422): Remove need for this.
+  // TODO(37715): Remove this.
   jsAst.Literal encodeRecipeWithVariablesReplaceByAny(
       ModularEmitter emitter, DartType dartType);
 
diff --git a/pkg/compiler/lib/src/js_backend/type_reference.dart b/pkg/compiler/lib/src/js_backend/type_reference.dart
new file mode 100644
index 0000000..4323e64
--- /dev/null
+++ b/pkg/compiler/lib/src/js_backend/type_reference.dart
@@ -0,0 +1,699 @@
+// 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.
+
+/// TypeReferences are 'holes' in the generated JavaScript that are filled in by
+/// the emitter with code to access a type.
+///
+/// The Dart code
+///
+///     foo1() => bar<int>(X<String>());
+///
+/// might be compiled to something like the following, with TypeReference1
+/// referring to the constructed type `X<String>`, and TypeReference2 referring
+/// to the method type argument `int`:
+///
+///     foo1: function() {
+///       return bar(new X(TypeReference1), TypeReference2);
+///     }
+///
+/// The dart method `foo2` would be compiled separately, with the generated code
+/// containing TypeReference3 referring to `int`:
+///
+///     foo2() => bar<int>(null);
+/// -->
+///     foo2: function() {
+///       return bar(null, TypeReference3);
+///     }
+///
+/// When the code for an output unit (main unit or deferred loaded unit) is
+/// assembled, there will also be a TypeReferenceResource 'hole', so the
+/// assembled looks something like
+///
+///     foo: function() {
+///       return bar(new X(TypeReference1), TypeReference2);
+///     }
+///     foo2: function() {
+///       return bar(null, TypeReference3);
+///     }
+///     ...
+///     TypeReferenceResource
+///
+/// The TypeReferenceFinalizer decides on a strategy for accessing the types. In
+/// most cases it is best to precompute the types and access them via a
+/// object. The TypeReference nodes are filled in with property access
+/// expressions and the TypeReferenceResource is filled in with the precomputed
+/// data, something like:
+///
+///     foo1: function() {
+///       return bar(new X(type$.X_String), type$.int);
+///     }
+///     foo2: function() {
+///       return bar(null, type$.int);
+///     }
+///     ...
+///     var type$ = {
+///       int: findType("int"),
+///       X_String: findType("X<String>")
+///     };
+///
+/// In minified mode, the properties `int` and `X_String` can be replaced by
+/// shorter names.
+library js_backend.type_reference;
+
+import 'package:front_end/src/api_unstable/dart2js.dart'
+    show $0, $9, $A, $Z, $_, $a, $z;
+
+import '../common_elements.dart' show CommonElements;
+import '../elements/entities.dart' show FunctionEntity;
+import '../elements/types.dart';
+import '../js/js.dart' as js;
+import '../js_emitter/code_emitter_task.dart' show Emitter;
+import '../js_model/type_recipe.dart'
+    show
+        TypeRecipe,
+        TypeExpressionRecipe,
+        SingletonTypeEnvironmentRecipe,
+        FullTypeEnvironmentRecipe;
+import '../serialization/serialization.dart';
+import '../util/util.dart' show Hashing;
+import 'runtime_types_new.dart' show RecipeEncoder;
+
+/// 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
+/// called from the fragment emitter. The replacement expression could be any
+/// expression, e.g. a call, or a reference to a variable, or property of a
+/// variable.
+class TypeReference extends js.DeferredExpression implements js.AstContainer {
+  static const String tag = 'type-reference';
+
+  /// [typeRecipe] is a recipe for a ground type or type environment.
+  final TypeRecipe typeRecipe;
+
+  // `true` if TypeReference is in code that initializes constant value.
+  // TODO(sra): Refine the concept of reference context.
+  bool forConstant = false;
+
+  js.Expression _value;
+
+  @override
+  final js.JavaScriptNodeSourceInformation sourceInformation;
+
+  TypeReference(this.typeRecipe) : sourceInformation = null;
+  TypeReference._(this.typeRecipe, this._value, this.sourceInformation);
+
+  factory TypeReference.readFromDataSource(DataSource source) {
+    source.begin(tag);
+    TypeRecipe recipe = source.readTypeRecipe();
+    source.end(tag);
+    return TypeReference(recipe);
+  }
+
+  void writeToDataSink(DataSink sink) {
+    sink.begin(tag);
+    sink.writeTypeRecipe(typeRecipe);
+    sink.end(tag);
+  }
+
+  set value(js.Expression value) {
+    assert(_value == null && value != null);
+    _value = value;
+  }
+
+  @override
+  js.Expression get value {
+    assert(_value != null, 'TypeReference is unassigned');
+    return _value;
+  }
+
+  // Precedence will be CALL or LEFT_HAND_SIDE depending on what expression the
+  // reference is resolved to.
+  @override
+  int get precedenceLevel => value.precedenceLevel;
+
+  @override
+  TypeReference withSourceInformation(
+      js.JavaScriptNodeSourceInformation newSourceInformation) {
+    if (newSourceInformation == sourceInformation) return this;
+    if (newSourceInformation == null) return this;
+    return TypeReference._(typeRecipe, _value, newSourceInformation);
+  }
+
+  @override
+  Iterable<js.Node> get containedNodes => _value == null ? const [] : [_value];
+}
+
+/// A [TypeReferenceResource] is a deferred JavaScript expression determined by
+/// the finalization of type references. It is the injection point for data or
+/// code to support type references. For example, if the
+/// [TypeReferenceFinalizer] decides that type should be referred to via a
+/// variable, the [TypeReferenceResource] would be set to code that declares and
+/// initializes the variable.
+class TypeReferenceResource extends js.DeferredExpression
+    implements js.AstContainer {
+  js.Expression _value;
+
+  @override
+  final js.JavaScriptNodeSourceInformation sourceInformation;
+
+  TypeReferenceResource() : sourceInformation = null;
+  TypeReferenceResource._(this._value, this.sourceInformation);
+
+  set value(js.Expression value) {
+    assert(_value == null && value != null);
+    _value = value;
+  }
+
+  @override
+  js.Expression get value {
+    assert(_value != null, 'TypeReferenceResource is unassigned');
+    return _value;
+  }
+
+  @override
+  int get precedenceLevel => value.precedenceLevel;
+
+  @override
+  TypeReferenceResource withSourceInformation(
+      js.JavaScriptNodeSourceInformation newSourceInformation) {
+    if (newSourceInformation == sourceInformation) return this;
+    if (newSourceInformation == null) return this;
+    return TypeReferenceResource._(_value, newSourceInformation);
+  }
+
+  @override
+  Iterable<js.Node> get containedNodes => _value == null ? const [] : [_value];
+
+  @override
+  void visitChildren<T>(js.NodeVisitor<T> visitor) {
+    _value?.accept<T>(visitor);
+  }
+
+  @override
+  void visitChildren1<R, A>(js.NodeVisitor1<R, A> visitor, A arg) {
+    _value?.accept1<R, A>(visitor, arg);
+  }
+}
+
+abstract class TypeReferenceFinalizer {
+  /// Collects TypeReference and TypeReferenceResource nodes from the JavaScript
+  /// AST [code];
+  void addCode(js.Node code);
+
+  /// Performs analysis on all collected TypeReference nodes finalizes the
+  /// values to expressions to access the types.
+  void finalize();
+}
+
+class TypeReferenceFinalizerImpl implements TypeReferenceFinalizer {
+  final Emitter _emitter;
+  final CommonElements _commonElements;
+  final RecipeEncoder _recipeEncoder;
+  final bool _minify;
+
+  /*late final*/ _TypeReferenceCollectorVisitor _visitor;
+  TypeReferenceResource _resource;
+
+  /// Maps the recipe (type expression) to the references with the same recipe.
+  /// Much of the algorithm's state is stored in the _ReferenceSet objects.
+  Map<TypeRecipe, _ReferenceSet> _referencesByRecipe = {};
+
+  TypeReferenceFinalizerImpl(
+      this._emitter, this._commonElements, this._recipeEncoder, this._minify) {
+    _visitor = _TypeReferenceCollectorVisitor(this);
+  }
+
+  @override
+  void addCode(js.Node code) {
+    code.accept(_visitor);
+  }
+
+  @override
+  void finalize() {
+    assert(_resource != null, 'TypeReferenceFinalizer needs resource');
+    _allocateNames();
+    _updateReferences();
+  }
+
+  // Called from collector visitor.
+  void _registerTypeReference(TypeReference node) {
+    TypeRecipe recipe = node.typeRecipe;
+    _ReferenceSet refs = _referencesByRecipe[recipe] ??= _ReferenceSet(recipe);
+    refs.count += 1;
+    refs._references.add(node);
+  }
+
+  // Called from collector visitor.
+  void _registerTypeReferenceResource(TypeReferenceResource node) {
+    assert(_resource == null);
+    _resource = node;
+  }
+
+  void _updateReferences() {
+    js.Expression loadTypeCall(TypeRecipe recipe) {
+      FunctionEntity helperElement = _commonElements.findType;
+      js.Expression recipeExpression =
+          _recipeEncoder.encodeGroundRecipe(_emitter, recipe);
+      js.Expression helper = _emitter.staticFunctionAccess(helperElement);
+      return js.js(r'#(#)', [helper, recipeExpression]);
+    }
+
+    // Emit generate-at-use references.
+    for (_ReferenceSet referenceSet in _referencesByRecipe.values) {
+      if (referenceSet.generateAtUse) {
+        TypeRecipe recipe = referenceSet.recipe;
+        js.Expression reference = loadTypeCall(recipe);
+        for (TypeReference ref in referenceSet._references) {
+          ref.value = reference;
+        }
+      }
+    }
+
+    List<_ReferenceSet> referenceSetsUsingProperties =
+        _referencesByRecipe.values.where((ref) => !ref.generateAtUse).toList();
+
+    // Sort by name (which is unique and mostly stable) so that similar recipes
+    // are grouped together.
+    referenceSetsUsingProperties.sort((a, b) => a.name.compareTo(b.name));
+
+    List<js.Property> properties = [];
+    for (_ReferenceSet referenceSet in referenceSetsUsingProperties) {
+      TypeRecipe recipe = referenceSet.recipe;
+      var propertyName = js.string(referenceSet.propertyName);
+      properties.add(js.Property(propertyName, loadTypeCall(recipe)));
+      var access = js.js('#.#', [typesHolderLocalName, propertyName]);
+      for (TypeReference ref in referenceSet._references) {
+        ref.value = access;
+      }
+    }
+    var initializer = js.ObjectInitializer(properties, isOneLiner: false);
+
+    _resource.value = js.js(r'var # = #',
+        [js.VariableDeclaration(typesHolderLocalName), initializer]);
+  }
+
+  // This is a top-level local name in the generated JavaScript top-level
+  // function, so will be minified automatically. The name should not collide
+  // with any other locals.
+  static const typesHolderLocalName = r'type$';
+
+  void _allocateNames() {
+    // Step 1. Filter out generate-at-use cases and allocate unique
+    // characteristic names to the rest.
+    List<_ReferenceSet> referencesInTable = [];
+    Set<String> usedNames = {};
+    for (_ReferenceSet referenceSet in _referencesByRecipe.values) {
+      // TODO(sra): Use more refined idea of context, e.g. single-use recipes in
+      // lazy initializers or 'throw' expressions.
+
+      // If a type is used only once from a constant then the findType can be a
+      // subexpression of constant since it will be evaluated only once and need
+      // not be stored anywhere else.
+      if (referenceSet.count == 1 &&
+          referenceSet._references.single.forConstant) continue;
+
+      String suggestedName = _RecipeToIdentifier().run(referenceSet.recipe);
+      if (usedNames.contains(suggestedName)) {
+        for (int i = 2; true; i++) {
+          String next = '${suggestedName}_$i';
+          if (usedNames.contains(next)) continue;
+          suggestedName = next;
+          break;
+        }
+      }
+      usedNames.add(suggestedName);
+      referenceSet.name = suggestedName;
+      referencesInTable.add(referenceSet);
+    }
+
+    if (!_minify) {
+      // 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.
+      for (_ReferenceSet referenceSet in referencesInTable) {
+        referenceSet.propertyName = referenceSet.name;
+      }
+      return;
+    }
+
+    // Step 2. Sort by frequency to arrange common entries have shorter property
+    // names.
+    List<_ReferenceSet> referencesByFrequency = referencesInTable.toList()
+      ..sort((a, b) {
+        assert(a.name != b.name);
+        int r = b.count.compareTo(a.count); // Decreasing frequency.
+        if (r != 0) return r;
+        return a.name.compareTo(b.name); // Tie-break with characteristic name.
+      });
+
+    for (var referenceSet in referencesByFrequency) {
+      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();
+    }
+  }
+
+  static int _hashCharacteristicString(String s) {
+    int hash = 0;
+    for (int i = 0; i < s.length; i++) {
+      hash = Hashing.mixHashCodeBits(hash, s.codeUnitAt(i));
+    }
+    return hash;
+  }
+
+  /// Returns an infinite sequence of property names in increasing size.
+  static Iterable<String> minifiedNameSequence() sync* {
+    List<int> nextName = [$a];
+
+    /// Increments the letter at [pos] in the current name. Also takes care of
+    /// overflows to the left. Returns the carry bit, i.e., it returns `true`
+    /// if all positions to the left have wrapped around.
+    ///
+    /// If [nextName] is initially 'a', this will generate the sequence
+    ///
+    ///     [a-zA-Z_]
+    ///     [a-zA-Z_][0-9a-zA-Z_]
+    ///     [a-zA-Z_][0-9a-zA-Z_][0-9a-zA-Z_]
+    ///     ...
+    bool incrementPosition(int pos) {
+      bool overflow = false;
+      if (pos < 0) return true;
+      int value = nextName[pos];
+      if (value == $9) {
+        value = $a;
+      } else if (value == $z) {
+        value = $A;
+      } else if (value == $Z) {
+        value = $_;
+      } else if (value == $_) {
+        overflow = incrementPosition(pos - 1);
+        value = (pos > 0) ? $0 : $a;
+      } else {
+        value++;
+      }
+      nextName[pos] = value;
+      return overflow;
+    }
+
+    while (true) {
+      yield String.fromCharCodes(nextName);
+      if (incrementPosition(nextName.length - 1)) {
+        nextName.add($0);
+      }
+    }
+  }
+}
+
+/// Set of references to a single recipe.
+class _ReferenceSet {
+  final TypeRecipe recipe;
+
+  // Number of times a TypeReference for [recipe] occurs in the tree-scan of the
+  // JavaScript ASTs.
+  int count = 0;
+
+  // It is possible for the JavaScript AST to be a DAG, so collect
+  // [TypeReference]s as set so we don't try to update one twice.
+  final Set<TypeReference> _references = Set.identity();
+
+  /// Characteristic name of the recipe - this can be used as a property name
+  /// for emitting unminified code, and as a stable hash source for minified
+  /// names.  [name] is `null` if [recipe] should always be generated at use.
+  String name;
+
+  /// Property name for 'indexing' into the precomputed types.
+  String propertyName;
+
+  /// A stable hash code that can be used for picking stable minified names.
+  int hash = 0;
+
+  _ReferenceSet(this.recipe);
+
+  // If we don't assign a name it means we should not precompute the recipe.
+  bool get generateAtUse => name == null;
+}
+
+/// Scans a JavaScript AST to collect all the TypeReference nodes.
+///
+/// The state is kept in the finalizer so that this scan could be extended to
+/// look for other deferred expressions in one pass.
+class _TypeReferenceCollectorVisitor extends js.BaseVisitor<void> {
+  final TypeReferenceFinalizerImpl _finalizer;
+
+  _TypeReferenceCollectorVisitor(this._finalizer);
+
+  @override
+  void visitNode(js.Node node) {
+    assert(node is! TypeReference);
+    assert(node is! TypeReferenceResource);
+    if (node is js.AstContainer) {
+      for (js.Node element in node.containedNodes) {
+        element.accept(this);
+      }
+    } else {
+      super.visitNode(node);
+    }
+  }
+
+  @override
+  void visitDeferredExpression(js.DeferredExpression node) {
+    if (node is TypeReference) {
+      _finalizer._registerTypeReference(node);
+    } else if (node is TypeReferenceResource) {
+      _finalizer._registerTypeReferenceResource(node);
+    } else {
+      visitNode(node);
+    }
+  }
+}
+
+/// Returns a valid JavaScript identifier characterizing the recipe. The names
+/// tend to look like the type expression with the non-identifier characters
+/// removed.  Separators 'of' and 'and' are sometimes used to separate complex
+/// types.
+///
+///     Map<int,int>        "Map_int_int"
+///     Map<int,List<int>>  "Map_of_int_and_List_int"
+///
+///
+/// For many common types the strings are unique, but this is not
+/// guaranteed. This needs to be disambiguated at a higher level.
+///
+/// Different types can have the same string if the types contain different
+/// interface types with the same name (i.e. from different libraries), or types
+/// with names that contain underscores or dollar signs. There is also some
+/// ambiguity in the generated names in the interest of keeping most names
+/// short, e.g. "FutureOr_int_Function" could be "FutureOr<int> Function()" or
+/// "FutureOr<int Function()>".
+class _RecipeToIdentifier extends DartTypeVisitor<void, DartType> {
+  final Map<DartType, int> _backrefs = Map.identity();
+  final List<String> _fragments = [];
+
+  static RegExp identifierStartRE = RegExp(r'[A-Za-z_$]');
+  static RegExp nonIdentifierRE = RegExp(r'[^A-Za-z0-9_$]');
+
+  String run(TypeRecipe recipe) {
+    if (recipe is TypeExpressionRecipe) {
+      _visit(recipe.type, null);
+    } else if (recipe is SingletonTypeEnvironmentRecipe) {
+      _add(r'$env');
+      _visit(recipe.type, null);
+    } else if (recipe is FullTypeEnvironmentRecipe) {
+      _add(r'$env');
+      if (recipe.classType != null) _visit(recipe.classType, null);
+      _add('${recipe.types.length}');
+      int index = 0;
+      for (DartType type in recipe.types) {
+        ++index;
+        _add('${index}');
+        _visit(type, null);
+      }
+    } else {
+      throw StateError('Unexpected recipe: $recipe');
+    }
+    String result = _fragments.join('_');
+    if (result.startsWith(identifierStartRE)) return result;
+    return 'z' + result;
+  }
+
+  void _add(String text) {
+    _fragments.add(text);
+  }
+
+  void _identifier(String text) {
+    _add(text.replaceAll(nonIdentifierRE, '_'));
+  }
+
+  bool _comma(bool needsComma) {
+    if (needsComma) _add('and');
+    return true;
+  }
+
+  void _visit(DartType type, DartType parent) {
+    type.accept(this, parent);
+  }
+
+  @override
+  void visitVoidType(covariant VoidType type, _) {
+    _add('void');
+  }
+
+  @override
+  void visitDynamicType(covariant DynamicType type, _) {
+    _add('dynamic');
+  }
+
+  @override
+  void visitAnyType(covariant AnyType type, _) {
+    _add('any');
+  }
+
+  @override
+  void visitTypeVariableType(covariant TypeVariableType type, DartType parent) {
+    if (parent != type.element.typeDeclaration) {
+      _identifier(type.element.typeDeclaration.name);
+    }
+    _identifier(type.element.name);
+  }
+
+  @override
+  void visitFunctionTypeVariable(covariant FunctionTypeVariable type, _) {
+    int index = type.index;
+    String name = index < 26 ? String.fromCharCode($A + index) : 'v\$${index}';
+    _add(name);
+  }
+
+  @override
+  void visitFunctionType(covariant FunctionType type, DartType parent) {
+    if (_dagCheck(type)) return;
+
+    _visit(type.returnType, type);
+    _add('Function');
+    var typeVariables = type.typeVariables;
+    if (typeVariables.isNotEmpty) {
+      bool needsComma = false;
+      for (FunctionTypeVariable typeVariable in typeVariables) {
+        needsComma = _comma(needsComma);
+        _visit(typeVariable, type);
+        DartType bound = typeVariable.bound;
+        if (!bound.isObject) {
+          _add('extends');
+          _visit(typeVariable.bound, typeVariable);
+        }
+      }
+    }
+    var parameterTypes = type.parameterTypes;
+    var optionalParameterTypes = type.optionalParameterTypes;
+    var namedParameters = type.namedParameters;
+    // TODO(fishythefish): Handle required named parameters.
+
+    if (optionalParameterTypes.isEmpty &&
+        namedParameters.isEmpty &&
+        parameterTypes.every(_isSimple)) {
+      // e.g.  "void_Function_int_int"
+      for (DartType parameterType in parameterTypes) {
+        _visit(parameterType, type);
+      }
+      return;
+    }
+    if (parameterTypes.length > 1) {
+      _add('${parameterTypes.length}');
+    }
+    bool needsComma = false;
+    for (DartType parameterType in parameterTypes) {
+      needsComma = _comma(needsComma);
+      _visit(parameterType, type);
+    }
+    if (optionalParameterTypes.isNotEmpty) {
+      _add(r'$opt');
+      bool needsOptionalComma = false;
+      for (DartType typeArgument in optionalParameterTypes) {
+        needsOptionalComma = _comma(needsOptionalComma);
+        _visit(typeArgument, type);
+      }
+    }
+    if (namedParameters.isNotEmpty) {
+      _add(r'$named');
+      bool needsNamedComma = false;
+      for (int index = 0; index < namedParameters.length; index++) {
+        needsNamedComma = _comma(needsNamedComma);
+        _identifier(namedParameters[index]);
+        _visit(type.namedParameterTypes[index], type);
+      }
+    }
+  }
+
+  @override
+  void visitInterfaceType(covariant InterfaceType type, _) {
+    var arguments = type.typeArguments;
+
+    // Don't bother DAG-checking (generating back-ref encodings) for interface
+    // types which 'print' as a single identifier.
+    if (arguments.isNotEmpty && _dagCheck(type)) return;
+
+    _identifier(type.element.name);
+
+    if (arguments.isEmpty) return;
+    if (arguments.length == 1) {
+      // e.g. "List_of_int_Function"
+      if (arguments.first is FunctionType) {
+        _add('of');
+      }
+      // e.g. "List_int"
+      _visit(arguments.first, type);
+      return;
+    }
+    if (arguments.every(_isSimple)) {
+      // e.g. "Map_String_String"
+      for (DartType argument in arguments) {
+        _visit(argument, type);
+      }
+      return;
+    }
+    // e.g "Map_of_String_and_int_Function"
+    _add('of');
+    bool needsComma = false;
+    for (DartType argument in arguments) {
+      needsComma = _comma(needsComma);
+      _visit(argument, type);
+    }
+  }
+
+  bool _dagCheck(DartType type) {
+    int /*?*/ ref = _backrefs[type];
+    if (ref != null) {
+      _add('\$$ref');
+      return true;
+    }
+    _backrefs[type] = _backrefs.length;
+    return false;
+  }
+
+  @override
+  void visitTypedefType(covariant TypedefType type, _) {
+    throw StateError('Typedefs should be elided $type');
+  }
+
+  /// Returns `true` for types which print as a single identifier.
+  static bool _isSimple(DartType type) {
+    return type is DynamicType ||
+        type is VoidType ||
+        type is AnyType ||
+        (type is InterfaceType && type.typeArguments.isEmpty);
+  }
+
+  @override
+  void visitFutureOrType(covariant FutureOrType type, _) {
+    _identifier('FutureOr');
+    _visit(type.typeArgument, type);
+  }
+}
diff --git a/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
index c3b28b7..98412ea 100644
--- a/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/parameter_stub_generator.dart
@@ -16,6 +16,8 @@
 import '../js_backend/interceptor_data.dart';
 import '../js_backend/runtime_types.dart';
 import '../js_backend/runtime_types_new.dart' show RecipeEncoder;
+import '../js_backend/type_reference.dart' show TypeReference;
+import '../js_model/type_recipe.dart' show TypeExpressionRecipe;
 import '../universe/call_structure.dart' show CallStructure;
 import '../universe/codegen_world_builder.dart';
 import '../universe/selector.dart' show Selector;
@@ -178,11 +180,9 @@
           DartType defaultType = _closedWorld.elementEnvironment
               .getTypeVariableDefaultType(typeVariable.element);
           if (_rtiRecipeEncoder != null) {
-            jsAst.Expression typeRti = _rtiRecipeEncoder.evaluateRecipe(
-                _emitter,
-                _rtiRecipeEncoder.encodeRecipeWithVariablesReplaceByAny(
-                    _emitter, defaultType));
-            targetArguments[count++] = typeRti;
+            defaultType = _eraseTypeVariablesToAny(defaultType);
+            targetArguments[count++] =
+                TypeReference(TypeExpressionRecipe(defaultType));
           } else {
             targetArguments[count++] = _rtiEncoder.getTypeRepresentation(
                 _emitter, defaultType, (_) => _emitter.constantReference(
@@ -244,6 +244,15 @@
     return new ParameterStubMethod(name, callName, function, element: member);
   }
 
+  DartType _eraseTypeVariablesToAny(DartType type) {
+    if (!type.containsTypeVariables) return type;
+    Set<TypeVariableType> variables = Set();
+    type.forEachTypeVariable(variables.add);
+    assert(variables.isNotEmpty);
+    return type.subst(
+        List.filled(variables.length, const AnyType()), variables.toList());
+  }
+
   // We fill the lists depending on possible/invoked selectors. For example,
   // take method foo:
   //    foo(a, b, {c, d});
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
index 441ab87..a18606f 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/fragment_emitter.dart
@@ -439,6 +439,9 @@
 // Adds the subtype rules for the new RTI.
 #typeRules;
 
+// Shared types need to be initialized before constants.
+#sharedTypeRtis;
+
 // Instantiates all constants.
 #constants;
 
@@ -537,6 +540,7 @@
 // Adds the subtype rules for the new RTI.
 #typeRules;
 
+#sharedTypeRtis;
 // Instantiates all constants of this deferred fragment.
 // Note that the constant-holder has been updated earlier and storing the
 // constant values in the constant-holder makes them available globally.
@@ -697,6 +701,8 @@
       'embeddedGlobalsPart2':
           emitEmbeddedGlobalsPart2(program, deferredLoadingState),
       'typeRules': emitTypeRules(fragment),
+      'sharedTypeRtis':
+          _options.experimentNewRti ? TypeReferenceResource() : [],
       'nativeSupport': program.needsNativeSupport
           ? emitNativeSupport(fragment)
           : new js.EmptyStatement(),
@@ -710,7 +716,7 @@
       'call2selector': js.quoteName(call2Name),
     });
     if (program.hasSoftDeferredClasses) {
-      return new js.Block([
+      mainCode = js.Block([
         js.js.statement(softDeferredBoilerplate, {
           'deferredGlobal': ModelEmitter.deferredInitializersGlobal,
           'softId': js.string(softDeferredId),
@@ -727,6 +733,7 @@
         mainCode
       ]);
     }
+    finalizeTypeReferences(mainCode);
     return mainCode;
   }
 
@@ -826,14 +833,26 @@
       'types': deferredTypes,
       'nativeSupport': nativeSupport,
       'typesOffset': _namer.typesOffsetName,
+      'sharedTypeRtis':
+          _options.experimentNewRti ? TypeReferenceResource() : [],
     });
 
     if (_options.experimentStartupFunctions) {
       code = js.Parentheses(code);
     }
+    finalizeTypeReferences(code);
     return code;
   }
 
+  void finalizeTypeReferences(js.Node code) {
+    if (!_options.experimentNewRti) return;
+
+    TypeReferenceFinalizer finalizer = TypeReferenceFinalizerImpl(
+        _emitter, _commonElements, _recipeEncoder, _options.enableMinification);
+    finalizer.addCode(code);
+    finalizer.finalize();
+  }
+
   /// Emits all holders, except for the static-state holder.
   ///
   /// The emitted holders contain classes (only the constructors) and all
diff --git a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
index 0a78680..c353cef 100644
--- a/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/startup_emitter/model_emitter.dart
@@ -54,6 +54,11 @@
 import '../../js_backend/runtime_types_codegen.dart';
 import '../../js_backend/runtime_types_new.dart'
     show RecipeEncoder, RecipeEncoderImpl, Ruleset, RulesetEncoder;
+import '../../js_backend/type_reference.dart'
+    show
+        TypeReferenceFinalizer,
+        TypeReferenceFinalizerImpl,
+        TypeReferenceResource;
 import '../../options.dart';
 import '../../universe/class_hierarchy.dart' show ClassHierarchy;
 import '../../universe/codegen_world_builder.dart' show CodegenWorld;
diff --git a/pkg/compiler/lib/src/js_model/type_recipe.dart b/pkg/compiler/lib/src/js_model/type_recipe.dart
index 9e17421..08cb3b0 100644
--- a/pkg/compiler/lib/src/js_model/type_recipe.dart
+++ b/pkg/compiler/lib/src/js_model/type_recipe.dart
@@ -8,6 +8,8 @@
 import '../elements/types.dart';
 import '../diagnostics/invariant.dart';
 import '../diagnostics/spannable.dart' show CURRENT_ELEMENT_SPANNABLE;
+import '../serialization/serialization.dart';
+import '../util/util.dart' show Hashing;
 
 abstract class TypeRecipeDomain {
   /// Detect if a recipe evaluates to its input environment.
@@ -132,6 +134,48 @@
 /// A TypeRecipe is evaluated against a type environment to produce either a
 /// type, or another type environment.
 abstract class TypeRecipe {
+  /// Tag used for identifying serialized [TypeRecipe] objects in a debugging
+  /// data stream.
+  static const String tag = 'type-recipe';
+
+  int /*?*/ _hashCode;
+
+  TypeRecipe();
+
+  @override
+  int get hashCode => _hashCode ??= _computeHashCode();
+
+  int _computeHashCode();
+
+  factory TypeRecipe.readFromDataSource(DataSource source) {
+    TypeRecipe recipe;
+    source.begin(tag);
+    _TypeRecipeKind kind = source.readEnum(_TypeRecipeKind.values);
+    switch (kind) {
+      case _TypeRecipeKind.expression:
+        recipe = TypeExpressionRecipe._readFromDataSource(source);
+        break;
+      case _TypeRecipeKind.singletonEnvironment:
+        recipe = SingletonTypeEnvironmentRecipe._readFromDataSource(source);
+        break;
+      case _TypeRecipeKind.fullEnvironment:
+        recipe = FullTypeEnvironmentRecipe._readFromDataSource(source);
+        break;
+    }
+    source.end(tag);
+    return recipe;
+  }
+
+  void writeToDataSink(DataSink sink) {
+    sink.begin(tag);
+    sink.writeEnum(_kind);
+    _writeToDataSink(sink);
+    sink.end(tag);
+  }
+
+  _TypeRecipeKind get _kind;
+  void _writeToDataSink(DataSink sink);
+
   /// Returns `true` is [recipeB] evaluated in an environment described by
   /// [structureB] gives the same type as [recipeA] evaluated in environment
   /// described by [structureA].
@@ -151,12 +195,29 @@
   }
 }
 
+enum _TypeRecipeKind { expression, singletonEnvironment, fullEnvironment }
+
 /// A recipe that yields a reified type.
 class TypeExpressionRecipe extends TypeRecipe {
   final DartType type;
 
   TypeExpressionRecipe(this.type);
 
+  static TypeExpressionRecipe _readFromDataSource(DataSource source) {
+    return TypeExpressionRecipe(source.readDartType());
+  }
+
+  @override
+  _TypeRecipeKind get _kind => _TypeRecipeKind.expression;
+
+  @override
+  void _writeToDataSink(DataSink sink) {
+    sink.writeDartType(type);
+  }
+
+  @override
+  int _computeHashCode() => type.hashCode * 7;
+
   @override
   bool operator ==(other) {
     return other is TypeExpressionRecipe && type == other.type;
@@ -176,6 +237,21 @@
 
   SingletonTypeEnvironmentRecipe(this.type);
 
+  static SingletonTypeEnvironmentRecipe _readFromDataSource(DataSource source) {
+    return SingletonTypeEnvironmentRecipe(source.readDartType());
+  }
+
+  @override
+  _TypeRecipeKind get _kind => _TypeRecipeKind.singletonEnvironment;
+
+  @override
+  void _writeToDataSink(DataSink sink) {
+    sink.writeDartType(type);
+  }
+
+  @override
+  int _computeHashCode() => type.hashCode * 11;
+
   @override
   bool operator ==(other) {
     return other is SingletonTypeEnvironmentRecipe && type == other.type;
@@ -201,6 +277,27 @@
 
   FullTypeEnvironmentRecipe({this.classType, this.types = const []});
 
+  static FullTypeEnvironmentRecipe _readFromDataSource(DataSource source) {
+    InterfaceType classType =
+        source.readDartType(allowNull: true) as InterfaceType;
+    List<DartType> types = source.readDartTypes(emptyAsNull: true) ?? const [];
+    return FullTypeEnvironmentRecipe(classType: classType, types: types);
+  }
+
+  @override
+  _TypeRecipeKind get _kind => _TypeRecipeKind.fullEnvironment;
+
+  @override
+  void _writeToDataSink(DataSink sink) {
+    sink.writeDartType(classType, allowNull: true);
+    sink.writeDartTypes(types, allowNull: false);
+  }
+
+  @override
+  int _computeHashCode() {
+    return Hashing.listHash(types, Hashing.objectHash(classType, 0));
+  }
+
   @override
   bool operator ==(other) {
     return other is FullTypeEnvironmentRecipe && _equal(this, other);
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index 1c3701c..4c899d4 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -781,7 +781,10 @@
     return _constantEvaluator ??= new Dart2jsConstantEvaluator(typeEnvironment,
         (ir.LocatedMessage message, List<ir.LocatedMessage> context) {
       reportLocatedMessage(reporter, message, context);
-    }, environment: _environment.toMap());
+    },
+        environment: _environment.toMap(),
+        enableTripleShift:
+            options.languageExperiments[ir.ExperimentalFlag.tripleShift]);
   }
 
   @override
diff --git a/pkg/compiler/lib/src/serialization/abstract_sink.dart b/pkg/compiler/lib/src/serialization/abstract_sink.dart
index 88c73d0..3a096fd 100644
--- a/pkg/compiler/lib/src/serialization/abstract_sink.dart
+++ b/pkg/compiler/lib/src/serialization/abstract_sink.dart
@@ -616,10 +616,17 @@
   @override
   void writeJsNode(js.Node value) {
     assert(_codegenWriter != null,
-        "Can not serialize a JS ndoe without a registered codegen writer.");
+        "Can not serialize a JS node without a registered codegen writer.");
     _codegenWriter.writeJsNode(this, value);
   }
 
+  @override
+  void writeTypeRecipe(TypeRecipe value) {
+    assert(_codegenWriter != null,
+        "Can not serialize a TypeRecipe without a registered codegen writer.");
+    _codegenWriter.writeTypeRecipe(this, value);
+  }
+
   /// Actual serialization of a section begin tag, implemented by subclasses.
   void _begin(String tag);
 
diff --git a/pkg/compiler/lib/src/serialization/abstract_source.dart b/pkg/compiler/lib/src/serialization/abstract_source.dart
index 7e46e16..b9fc97b 100644
--- a/pkg/compiler/lib/src/serialization/abstract_source.dart
+++ b/pkg/compiler/lib/src/serialization/abstract_source.dart
@@ -759,6 +759,13 @@
     return _codegenReader.readJsNode(this);
   }
 
+  @override
+  TypeRecipe readTypeRecipe() {
+    assert(_codegenReader != null,
+        "Can not deserialize a TypeRecipe without a registered codegen reader.");
+    return _codegenReader.readTypeRecipe(this);
+  }
+
   /// Actual deserialization of a section begin tag, implemented by subclasses.
   void _begin(String tag);
 
diff --git a/pkg/compiler/lib/src/serialization/serialization.dart b/pkg/compiler/lib/src/serialization/serialization.dart
index 9f5b8ab..7c37416 100644
--- a/pkg/compiler/lib/src/serialization/serialization.dart
+++ b/pkg/compiler/lib/src/serialization/serialization.dart
@@ -22,6 +22,7 @@
 import '../js/js.dart' as js;
 import '../js_model/closure.dart';
 import '../js_model/locals.dart';
+import '../js_model/type_recipe.dart' show TypeRecipe;
 
 part 'abstract_sink.dart';
 part 'abstract_source.dart';
@@ -432,6 +433,11 @@
   /// This feature is only available a [CodegenWriter] has been registered.
   void writeJsNodeOrNull(js.Node value);
 
+  /// Writes TypeRecipe [value] to this data sink.
+  ///
+  /// This feature is only available a [CodegenWriter] has been registered.
+  void writeTypeRecipe(TypeRecipe value);
+
   /// Register an [EntityWriter] with this data sink for non-default encoding
   /// of entity references.
   void registerEntityWriter(EntityWriter writer);
@@ -836,6 +842,11 @@
   ///
   /// This feature is only available a [CodegenReader] has been registered.
   js.Node readJsNodeOrNull();
+
+  /// Reads a [TypeRecipe] value from this data source.
+  ///
+  /// This feature is only available a [CodegenReader] has been registered.
+  TypeRecipe readTypeRecipe();
 }
 
 /// Interface used for looking up entities by index during deserialization.
@@ -921,6 +932,7 @@
   AbstractValue readAbstractValue(DataSource source);
   OutputUnit readOutputUnitReference(DataSource source);
   js.Node readJsNode(DataSource source);
+  TypeRecipe readTypeRecipe(DataSource source);
 }
 
 /// Interface used for writing codegen only data during serialization.
@@ -928,4 +940,5 @@
   void writeAbstractValue(DataSink sink, AbstractValue value);
   void writeOutputUnitReference(DataSink sink, OutputUnit value);
   void writeJsNode(DataSink sink, js.Node node);
+  void writeTypeRecipe(DataSink sink, TypeRecipe recipe);
 }
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index b23b29c..3e9e4fc 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -4693,9 +4693,10 @@
       stack.add(graph.addConstantNull(closedWorld));
       return;
     }
-    // TODO(sra): Introduce 'any' type.
+    // TODO(sra): This should be JSArray<any>, created via
+    // _elementEnvironment.getJsInteropType(_elementEnvironment.jsArrayClass);
     InterfaceType interopType =
-        InterfaceType(_commonElements.jsArrayClass, [DynamicType()]);
+        InterfaceType(_commonElements.jsArrayClass, [const DynamicType()]);
     SourceInformation sourceInformation =
         _sourceInformationBuilder.buildCall(invocation, invocation);
     HInstruction rti =
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 71ed092..90ffef5 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -29,6 +29,7 @@
 import '../js_backend/runtime_types_codegen.dart';
 import '../js_backend/runtime_types_new.dart'
     show RecipeEncoder, RecipeEncoding, indexTypeVariable;
+import '../js_backend/type_reference.dart' show TypeReference;
 import '../js_emitter/code_emitter_task.dart' show ModularEmitter;
 import '../js_model/elements.dart' show JGeneratorBody;
 import '../js_model/type_recipe.dart';
@@ -3401,14 +3402,10 @@
 
   @override
   visitLoadType(HLoadType node) {
-    FunctionEntity helperElement = _commonElements.findType;
-    _registry.registerStaticUse(
-        new StaticUse.staticInvoke(helperElement, CallStructure.ONE_ARG));
-    js.Expression recipe =
-        _rtiRecipeEncoder.encodeGroundRecipe(_emitter, node.typeExpression);
-    js.Expression helper = _emitter.staticFunctionAccess(helperElement);
-    push(js.js(r'#(#)', [helper, recipe]).withSourceInformation(
-        node.sourceInformation));
+    // 'findType' will be called somewhere to initialize the type reference.
+    _registry.registerStaticUse(StaticUse.staticInvoke(
+        _commonElements.findType, CallStructure.ONE_ARG));
+    push(TypeReference(node.typeExpression));
   }
 
   @override
diff --git a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
index a16575c..32c88dc 100644
--- a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
+++ b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
@@ -176,17 +176,51 @@
     return null;
   }
 
-  HInstruction findDominator(Iterable<HInstruction> instructions) {
-    HInstruction result;
-    L1:
-    for (HInstruction candidate in instructions) {
-      for (HInstruction current in instructions) {
-        if (current != candidate && !candidate.dominates(current)) continue L1;
+  // Returns the element of [instructions] that dominates all other elements, if
+  // such an instruction exists.  [dominator] is an optional hint of an
+  // instruction that dominates all elements of [instructions], but that is not
+  // one of [instructions].
+  HInstruction findDominatingInstruction(List<HInstruction> instructions,
+      [HInstruction dominator]) {
+    // If there is a single dominator instruction, it will be in a block which
+    // dominates all the other instruction's blocks. This means that the
+    // dominatorDfsIn..dominatorDfsOut range will include all the other ranges,
+    // i.e. the block must have the minimum dominatorDfsIn and maximum
+    // dominatorDfsOut.  We can test this in a single pass over the candidates.
+    HInstruction bestInstruction = instructions.first;
+    HBasicBlock bestBlock = bestInstruction.block;
+    int maxDfsOut = bestBlock.dominatorDfsOut;
+    for (int i = 1; i < instructions.length; i++) {
+      HInstruction candidate = instructions[i];
+      if (candidate == bestInstruction) continue; // ignore repeated uses
+      HBasicBlock block = candidate.block;
+      if (block == bestBlock) {
+        bestInstruction = null; // There are two instructions in bestBlock
+        continue;
       }
-      result = candidate;
-      break;
+      if (maxDfsOut < block.dominatorDfsOut) maxDfsOut = block.dominatorDfsOut;
+      if (block.dominatorDfsIn < bestBlock.dominatorDfsIn) {
+        bestInstruction = candidate;
+        bestBlock = block;
+      }
     }
-    return result;
+
+    // [bestBlock] only dominates if all other blocks are in range.
+    if (maxDfsOut > bestBlock.dominatorDfsOut) return null;
+
+    // If best block had a single candidate instruction, we can return it.
+    if (bestInstruction != null) return bestInstruction;
+
+    // If multiple instructions are present in bestBlock, we scan bestBlock from
+    // the start to find first instruction. If the [dominator] hint is in the
+    // same block, can start from there instead.
+    Set<HInstruction> set =
+        instructions.where((i) => i.block == bestBlock).toSet();
+    HInstruction current =
+        (dominator?.block == bestBlock) ? dominator : bestBlock.first;
+    while (current != null && !set.contains(current)) current = current.next;
+    assert(current != null);
+    return current;
   }
 
   static int useCount(HInstruction user, HInstruction used) =>
@@ -222,7 +256,7 @@
     // a HTypeKnown instruction.
 
     Set<ClassEntity> interceptedClasses;
-    HInstruction dominator = findDominator(node.usedBy);
+    HInstruction dominator = findDominatingInstruction(node.usedBy, node);
     // If there is a call that dominates all other uses, we can use just the
     // selector of that instruction.
     if (dominator is HInvokeDynamic &&
diff --git a/pkg/compiler/lib/src/ssa/ssa.dart b/pkg/compiler/lib/src/ssa/ssa.dart
index 5fb6fe9..66a4f37 100644
--- a/pkg/compiler/lib/src/ssa/ssa.dart
+++ b/pkg/compiler/lib/src/ssa/ssa.dart
@@ -17,6 +17,7 @@
 import '../js/rewrite_async.dart';
 import '../js_backend/backend.dart' show CodegenInputs, FunctionCompiler;
 import '../js_backend/namer.dart' show ModularNamer, ModularNamerImpl;
+import '../js_backend/type_reference.dart' show TypeReference;
 import '../js_emitter/code_emitter_task.dart' show ModularEmitter;
 import '../js_emitter/startup_emitter/emitter.dart' show ModularEmitterImpl;
 import '../js_model/elements.dart';
@@ -184,21 +185,11 @@
   }
 
   List<js.Expression> _fetchItemTypeNewRti(
-      CodegenInputs codegen,
-      CommonElements commonElements,
-      CodegenRegistry registry,
-      ModularEmitter emitter,
-      DartType type) {
+      CommonElements commonElements, CodegenRegistry registry, DartType type) {
     if (type == null) return null;
-
-    FunctionEntity helperElement = commonElements.findType;
     registry.registerStaticUse(
-        new StaticUse.staticInvoke(helperElement, CallStructure.ONE_ARG));
-    js.Expression recipe = codegen.rtiRecipeEncoder
-        .encodeGroundRecipe(emitter, TypeExpressionRecipe(type));
-    js.Expression helper = emitter.staticFunctionAccess(helperElement);
-    var ast = js.js(r'#(#)', [helper, recipe]);
-    return <js.Expression>[ast];
+        StaticUse.staticInvoke(commonElements.findType, CallStructure.ONE_ARG));
+    return [TypeReference(TypeExpressionRecipe(type))];
   }
 
   AsyncRewriter _makeAsyncRewriter(
@@ -216,8 +207,7 @@
     FunctionEntity completerFactory = commonElements.asyncAwaitCompleterFactory;
 
     List<js.Expression> itemTypeExpression = _options.experimentNewRti
-        ? _fetchItemTypeNewRti(
-            codegen, commonElements, registry, emitter, elementType)
+        ? _fetchItemTypeNewRti(commonElements, registry, elementType)
         : _fetchItemType(codegen, emitter, elementType);
 
     AsyncRewriter rewriter = new AsyncRewriter(_reporter, element,
@@ -254,8 +244,7 @@
       DartType asyncTypeParameter,
       js.Name name) {
     List<js.Expression> itemTypeExpression = _options.experimentNewRti
-        ? _fetchItemTypeNewRti(
-            codegen, commonElements, registry, emitter, asyncTypeParameter)
+        ? _fetchItemTypeNewRti(commonElements, registry, asyncTypeParameter)
         : _fetchItemType(codegen, emitter, asyncTypeParameter);
 
     SyncStarRewriter rewriter = new SyncStarRewriter(_reporter, element,
@@ -291,8 +280,7 @@
       DartType asyncTypeParameter,
       js.Name name) {
     List<js.Expression> itemTypeExpression = _options.experimentNewRti
-        ? _fetchItemTypeNewRti(
-            codegen, commonElements, registry, emitter, asyncTypeParameter)
+        ? _fetchItemTypeNewRti(commonElements, registry, asyncTypeParameter)
         : _fetchItemType(codegen, emitter, asyncTypeParameter);
 
     AsyncStarRewriter rewriter = new AsyncStarRewriter(_reporter, element,
diff --git a/pkg/dev_compiler/lib/dev_compiler.dart b/pkg/dev_compiler/lib/dev_compiler.dart
new file mode 100644
index 0000000..7859a56
--- /dev/null
+++ b/pkg/dev_compiler/lib/dev_compiler.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.
+
+// The dev_compiler does not have a publishable public API, instead this is
+// intended for other consumers within the Dart SDK.
+export 'src/kernel/target.dart' show DevCompilerTarget;
diff --git a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
index 4fe742b..198ea15 100644
--- a/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/code_generator.dart
@@ -16,7 +16,6 @@
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/ast/token.dart' show StringToken;
 import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/handle.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/constant.dart'
     show DartObject, DartObjectImpl;
@@ -2269,14 +2268,11 @@
             p.parameterKind))
         .toList();
 
-    var function = FunctionElementImpl("", -1)
-      ..isSynthetic = true
-      ..returnType = element.returnType
-      // TODO(jmesserly): do covariant type parameter bounds also need to be
-      // reified as `Object`?
-      ..shareTypeParameters(element.typeParameters)
-      ..parameters = parameters;
-    return function.type = FunctionTypeImpl(function);
+    return FunctionTypeImpl.synthetic(
+      element.returnType,
+      element.typeParameters,
+      parameters,
+    );
   }
 
   js_ast.Expression _constructorName(String name) {
@@ -6740,9 +6736,7 @@
   TemporaryVariableElement.forNode(
       Identifier name, this.jsVariable, Element enclosingElement)
       : super.forNode(name) {
-    this.enclosingElement = enclosingElement is ElementHandle
-        ? enclosingElement.actualElement
-        : enclosingElement;
+    this.enclosingElement = enclosingElement;
   }
 
   @override
diff --git a/pkg/dev_compiler/lib/src/analyzer/element_helpers.dart b/pkg/dev_compiler/lib/src/analyzer/element_helpers.dart
index 5723e17..c100c2f 100644
--- a/pkg/dev_compiler/lib/src/analyzer/element_helpers.dart
+++ b/pkg/dev_compiler/lib/src/analyzer/element_helpers.dart
@@ -49,32 +49,22 @@
 /// meaningful type, so we need to work around that.
 DartType instantiateElementTypeToBounds(
     Dart2TypeSystem rules, TypeDefiningElement element) {
-  Element e = element;
-  if (e is TypeParameterizedElement) {
-    // TODO(jmesserly): we can't use `instantiateToBounds` because typedefs do
-    // not include their type parameters, for example:
-    //
-    //     typedef void void Func<T>(T x);               // Dart 1 syntax.
-    //     typedef void GenericFunc<T> = S Func<S>(T x); // Dart 2 syntax.
-    //
-    // There is no way to get a type that has `<T>` as a type formal from the
-    // element (without constructing it ourselves).
-    //
-    // Futhermore, the second line is represented by a GenericTypeAliasElement,
-    // and its type getter does not even include its own type formals `<S>`.
-    // That has to be worked around using `.function.type`.
-    DartType type;
-    if (e is GenericTypeAliasElement) {
-      type = e.function.type;
-    } else if (e is FunctionTypedElement) {
-      type = e.type;
-    } else if (e is ClassElement) {
-      type = getLegacyRawClassType(e);
+  if (element is TypeParameterizedElement) {
+    if (element is ClassElement) {
+      var typeArguments = rules.instantiateTypeFormalsToBounds2(element);
+      return element.instantiate(
+        typeArguments: typeArguments,
+        nullabilitySuffix: NullabilitySuffix.star,
+      );
+    } else if (element is GenericTypeAliasElement) {
+      var typeArguments = rules.instantiateTypeFormalsToBounds2(element);
+      return element.instantiate2(
+        typeArguments: typeArguments,
+        nullabilitySuffix: NullabilitySuffix.star,
+      );
+    } else {
+      throw StateError('${element.runtimeType}');
     }
-    var bounds = rules.instantiateTypeFormalsToBounds(e.typeParameters);
-    if (bounds == null) return type;
-    return type.substitute2(
-        bounds, TypeParameterTypeImpl.getTypes(e.typeParameters));
   }
   return getLegacyElementType(element);
 }
diff --git a/pkg/dev_compiler/test/modular_ddc_suite.dart b/pkg/dev_compiler/test/modular_ddc_suite.dart
index 4c2a413..e525eb2 100644
--- a/pkg/dev_compiler/test/modular_ddc_suite.dart
+++ b/pkg/dev_compiler/test/modular_ddc_suite.dart
@@ -146,7 +146,7 @@
       Uri output = toUri(module, jsId);
 
       List<String> args = [
-        '--packages=${sdkRoot.toFilePath()}/.packages',
+        '--packages=${sdkRoot.toFilePath()}.packages',
         _dartdevcScript,
         '--modules=es6',
         '--summarize',
diff --git a/pkg/dev_compiler/tool/patch_sdk.dart b/pkg/dev_compiler/tool/patch_sdk.dart
index 543e90d..db3ca57 100755
--- a/pkg/dev_compiler/tool/patch_sdk.dart
+++ b/pkg/dev_compiler/tool/patch_sdk.dart
@@ -482,7 +482,7 @@
   // TODO(jmesserly): fix SdkLibrariesReader_LibraryBuilder in Analyzer.
   // It doesn't understand optional new/const in Dart 2. For now, we keep
   // redundant `const` in tool/input_sdk/libraries.dart as a workaround.
-  var libraryBuilder = SdkLibrariesReader_LibraryBuilder(true);
+  var libraryBuilder = SdkLibrariesReader_LibraryBuilder();
   parseString(content: contents).unit.accept(libraryBuilder);
   return libraryBuilder.librariesMap.sdkLibraries;
 }
diff --git a/pkg/dev_compiler/web/source_map_stack_trace.dart b/pkg/dev_compiler/web/source_map_stack_trace.dart
index 57a4016..649f30a 100644
--- a/pkg/dev_compiler/web/source_map_stack_trace.dart
+++ b/pkg/dev_compiler/web/source_map_stack_trace.dart
@@ -70,10 +70,59 @@
   }).where((frame) => frame != null));
 }
 
+final escapedPipe = '\$124';
+final escapedPound = '\$35';
+
 /// Reformats a JS member name to make it look more Dart-like.
+///
+/// Logic copied from build/build_web_compilers/web/stack_trace_mapper.dart.
+/// TODO(https://github.com/dart-lang/sdk/issues/38869): Remove this logic when
+/// DDC stack trace deobfuscation is overhauled.
 String _prettifyMember(String member) {
   var last = member.lastIndexOf('.');
   if (last < 0) return member;
   var suffix = member.substring(last + 1);
-  return suffix == 'fn' ? member : suffix;
+  member = suffix == 'fn' ? member : suffix;
+  // We avoid unescaping the entire member here due to DDC's deduping mechanism
+  // introducing trailing $N.
+  member = member.replaceAll(escapedPipe, '|');
+  return member.contains('|') ? _prettifyExtension(member) : member;
+}
+
+/// Reformats a JS member name as an extension method invocation.
+String _prettifyExtension(String member) {
+  var isSetter = false;
+  var pipeIndex = member.indexOf('|');
+  var spaceIndex = member.indexOf(' ');
+  var poundIndex = member.indexOf('escapedPound');
+  if (spaceIndex >= 0) {
+    // Here member is a static field or static getter/setter.
+    isSetter = member.substring(0, spaceIndex) == 'set';
+    member = member.substring(spaceIndex + 1, member.length);
+  } else if (poundIndex >= 0) {
+    // Here member is a tearoff or local property getter/setter.
+    isSetter = member.substring(pipeIndex + 1, poundIndex) == 'set';
+    member = member.replaceRange(pipeIndex + 1, poundIndex + 3, '');
+  } else {
+    var body = member.substring(pipeIndex + 1, member.length);
+    if (body.startsWith('unary') || body.startsWith('\$')) {
+      // Here member's an operator, so it's safe to unescape everything lazily.
+      member = _unescape(member);
+    }
+  }
+  member = member.replaceAll('|', '.');
+  return isSetter ? '$member=' : member;
+}
+
+/// Unescapes a DDC-escaped JS identifier name.
+///
+/// Identifier names that contain illegal JS characters are escaped by DDC to a
+/// decimal representation of the symbol's UTF-16 value.
+/// Warning: this greedily escapes characters, so it can be unsafe in the event
+/// that an escaped sequence precedes a number literal in the JS name.
+String _unescape(String name) {
+  return name.replaceAllMapped(
+      RegExp(r'\$[0-9]+'),
+      (m) =>
+          String.fromCharCode(int.parse(name.substring(m.start + 1, m.end))));
 }
diff --git a/pkg/front_end/analysis_options_no_lints.yaml b/pkg/front_end/analysis_options_no_lints.yaml
index 5317b91..b2e05b8 100644
--- a/pkg/front_end/analysis_options_no_lints.yaml
+++ b/pkg/front_end/analysis_options_no_lints.yaml
@@ -4,6 +4,7 @@
 
 analyzer:
   exclude:
+    - test/analyser_ignored/**
     - test/extensions/data/**
     - test/flow_analysis/definite_assignment/data/**
     - test/flow_analysis/nullability/data/**
@@ -13,6 +14,7 @@
     - testcases/**
     - test/id_testing/data/**
     - test/language_versioning/data/**
+    - test/patching/data/**
   errors:
     # Allow having TODOs in the code
     todo: ignore
diff --git a/pkg/front_end/lib/src/api_prototype/compiler_options.dart b/pkg/front_end/lib/src/api_prototype/compiler_options.dart
index 301536d..60ea195 100644
--- a/pkg/front_end/lib/src/api_prototype/compiler_options.dart
+++ b/pkg/front_end/lib/src/api_prototype/compiler_options.dart
@@ -209,6 +209,14 @@
   /// Typically used by developers to debug internals of the compiler.
   bool throwOnWarningsForDebugging = false;
 
+  /// For the [throwOnErrorsForDebugging] or [throwOnWarningsForDebugging]
+  /// options, skip this number of otherwise fatal diagnostics without throwing.
+  /// I.e. the default value of 0 means throw on the first fatal diagnostic.
+  ///
+  /// If the value is negative, print a stack trace for every fatal
+  /// diagnostic, but do not stop the compilation.
+  int skipForDebugging = 0;
+
   /// Whether to generate bytecode.
   bool bytecode = false;
 
diff --git a/pkg/front_end/lib/src/api_prototype/incremental_kernel_generator.dart b/pkg/front_end/lib/src/api_prototype/incremental_kernel_generator.dart
index 0cf8a93..26b7a35 100644
--- a/pkg/front_end/lib/src/api_prototype/incremental_kernel_generator.dart
+++ b/pkg/front_end/lib/src/api_prototype/incremental_kernel_generator.dart
@@ -17,18 +17,25 @@
 
 import '../fasta/incremental_compiler.dart' show IncrementalCompiler;
 
+import '../fasta/incremental_serializer.dart' show IncrementalSerializer;
+
 import '../fasta/scanner/string_scanner.dart' show StringScanner;
 
 import 'compiler_options.dart' show CompilerOptions;
 
+export '../fasta/incremental_serializer.dart' show IncrementalSerializer;
+
 abstract class IncrementalKernelGenerator {
   factory IncrementalKernelGenerator(CompilerOptions options, Uri entryPoint,
-      [Uri initializeFromDillUri, bool outlineOnly]) {
+      [Uri initializeFromDillUri,
+      bool outlineOnly,
+      IncrementalSerializer incrementalSerializer]) {
     return new IncrementalCompiler(
         new CompilerContext(
             new ProcessedOptions(options: options, inputs: [entryPoint])),
         initializeFromDillUri,
-        outlineOnly);
+        outlineOnly,
+        incrementalSerializer);
   }
 
   /// Initialize the incremental compiler from a component.
@@ -37,7 +44,7 @@
   /// platform will be loaded.
   factory IncrementalKernelGenerator.fromComponent(
       CompilerOptions options, Uri entryPoint, Component component,
-      [bool outlineOnly]) {
+      [bool outlineOnly, IncrementalSerializer incrementalSerializer]) {
     return new IncrementalCompiler.fromComponent(
         new CompilerContext(
             new ProcessedOptions(options: options, inputs: [entryPoint])),
diff --git a/pkg/front_end/lib/src/api_unstable/vm.dart b/pkg/front_end/lib/src/api_unstable/vm.dart
index 38dc042..6da41e1 100644
--- a/pkg/front_end/lib/src/api_unstable/vm.dart
+++ b/pkg/front_end/lib/src/api_unstable/vm.dart
@@ -17,7 +17,7 @@
 export '../api_prototype/front_end.dart' show CompilerResult;
 
 export '../api_prototype/incremental_kernel_generator.dart'
-    show IncrementalKernelGenerator, isLegalIdentifier;
+    show IncrementalKernelGenerator, IncrementalSerializer, isLegalIdentifier;
 
 export '../api_prototype/kernel_generator.dart'
     show kernelForModule, kernelForProgram;
@@ -54,8 +54,6 @@
         templateFfiStructGeneric,
         templateFfiTypeInvalid,
         templateFfiTypeMismatch,
-        templateFfiTypeUnsized,
-        templateFfiWrongStructInheritance,
         templateIllegalRecursiveType;
 
 export '../fasta/hybrid_file_system.dart' show HybridFileSystem;
diff --git a/pkg/front_end/lib/src/base/processed_options.dart b/pkg/front_end/lib/src/base/processed_options.dart
index 28c54a7..413f0b2 100644
--- a/pkg/front_end/lib/src/base/processed_options.dart
+++ b/pkg/front_end/lib/src/base/processed_options.dart
@@ -49,6 +49,7 @@
         noLength,
         templateCannotReadSdkSpecification,
         templateCantReadFile,
+        templateDebugTrace,
         templateInputFileNotFound,
         templateInternalProblemUnsupported,
         templatePackagesFileFormat,
@@ -184,6 +185,9 @@
 
   bool get errorOnUnevaluatedConstant => _raw.errorOnUnevaluatedConstant;
 
+  /// The number of fatal diagnostics encountered so far.
+  int fatalDiagnosticCount = 0;
+
   /// Initializes a [ProcessedOptions] object wrapping the given [rawOptions].
   ProcessedOptions({CompilerOptions options, List<Uri> inputs, this.output})
       : this._raw = options ?? new CompilerOptions(),
@@ -223,8 +227,18 @@
     }
     reportDiagnosticMessage(format(message, severity, context));
     if (command_line_reporting.shouldThrowOn(severity)) {
-      throw new DebugAbort(
-          message.uri, message.charOffset, severity, StackTrace.current);
+      if (fatalDiagnosticCount++ < _raw.skipForDebugging) {
+        // Skip this one. The interesting one comes later.
+        return;
+      }
+      if (_raw.skipForDebugging < 0) {
+        print(templateDebugTrace
+            .withArguments("$severity", "${StackTrace.current}")
+            .message);
+      } else {
+        throw new DebugAbort(
+            message.uri, message.charOffset, severity, StackTrace.current);
+      }
     }
   }
 
diff --git a/pkg/front_end/lib/src/fasta/builder/builder.dart b/pkg/front_end/lib/src/fasta/builder/builder.dart
index 58fcf09..53e5418 100644
--- a/pkg/front_end/lib/src/fasta/builder/builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/builder.dart
@@ -1,72 +1,310 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
+// 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.
 
-library fasta.builder;
+library fasta.declaration;
 
-export '../identifiers.dart'
-    show
-        Identifier,
-        InitializedIdentifier,
-        QualifiedName,
-        deprecated_extractToken,
-        flattenName;
+import '../problems.dart' show unsupported;
 
-export '../scope.dart' show AccessErrorBuilder, Scope, ScopeBuilder;
+/// Dummy class to help deprecate [Builder.target].
+abstract class UnrelatedTarget {}
 
-export 'builtin_type_builder.dart' show BuiltinTypeBuilder;
+abstract class Builder {
+  /// Used when multiple things with the same name are declared within the same
+  /// parent. Only used for top-level and class-member declarations, not for
+  /// block scopes.
+  Builder next;
 
-export 'class_builder.dart' show ClassBuilder;
+  Builder get parent;
 
-export 'constructor_reference_builder.dart' show ConstructorReferenceBuilder;
+  Uri get fileUri;
 
-export 'declaration.dart' show Builder;
+  int get charOffset;
 
-export 'dynamic_type_builder.dart' show DynamicTypeBuilder;
+  get target;
 
-export 'enum_builder.dart' show EnumBuilder, EnumConstantInfo;
+  Builder get origin;
 
-export 'field_builder.dart' show FieldBuilder;
+  String get fullNameForErrors;
 
-export 'formal_parameter_builder.dart' show FormalParameterBuilder;
+  bool get hasProblem;
 
-export 'procedure_builder.dart'
-    show
-        FunctionBuilder,
-        ConstructorBuilder,
-        ProcedureBuilder,
-        RedirectingFactoryBuilder;
+  bool get isConst;
 
-export 'function_type_builder.dart' show FunctionTypeBuilder;
+  bool get isConstructor;
 
-export 'invalid_type_builder.dart' show InvalidTypeBuilder;
+  bool get isFactory;
 
-export 'library_builder.dart' show LibraryBuilder;
+  bool get isField;
 
-export 'member_builder.dart' show MemberBuilder;
+  bool get isFinal;
 
-export 'metadata_builder.dart' show MetadataBuilder;
+  bool get isGetter;
 
-export 'mixin_application_builder.dart' show MixinApplicationBuilder;
+  /// Returns `true` if this builder is an extension declaration.
+  ///
+  /// For instance `B` in:
+  ///
+  ///    class A {}
+  ///    extension B on A {}
+  ///
+  bool get isExtension;
 
-export 'modifier_builder.dart' show ModifierBuilder;
+  /// Returns `true` if this builder is a member of a class, mixin, or extension
+  /// declaration.
+  ///
+  /// For instance `A.constructor`, `method1a`, `method1b`, `method2a`,
+  /// `method2b`, `method3a`, and `method3b` in:
+  ///
+  ///     class A {
+  ///       A.constructor();
+  ///       method1a() {}
+  ///       static method1b() {}
+  ///     }
+  ///     mixin B {
+  ///       method2a() {}
+  ///       static method2b() {}
+  ///     }
+  ///     extends C on A {
+  ///       method3a() {}
+  ///       static method3b() {}
+  ///     }
+  ///
+  bool get isDeclarationMember;
 
-export 'name_iterator.dart' show NameIterator;
+  /// Returns `true` if this builder is a member of a class or mixin
+  /// declaration.
+  ///
+  /// For instance `A.constructor`, `method1a`, `method1b`, `method2a` and
+  /// `method2b` in:
+  ///
+  ///     class A {
+  ///       A.constructor();
+  ///       method1a() {}
+  ///       static method1b() {}
+  ///     }
+  ///     mixin B {
+  ///       method2a() {}
+  ///       static method2b() {}
+  ///     }
+  ///     extends C on A {
+  ///       method3a() {}        // Not a class member.
+  ///       static method3b() {} // Not a class member.
+  ///     }
+  ///
+  bool get isClassMember;
 
-export 'named_type_builder.dart' show NamedTypeBuilder;
+  /// Returns `true` if this builder is a member of an extension declaration.
+  ///
+  /// For instance `method3a` and `method3b` in:
+  ///
+  ///     class A {
+  ///       A.constructor();     // Not an extension member.
+  ///       method1a() {}        // Not an extension member.
+  ///       static method1b() {} // Not an extension member.
+  ///     }
+  ///     mixin B {
+  ///       method2a() {}        // Not an extension member.
+  ///       static method2b() {} // Not an extension member.
+  ///     }
+  ///     extends C on A {
+  ///       method3a() {}
+  ///       static method3b() {}
+  ///     }
+  ///
+  bool get isExtensionMember;
 
-export 'nullability_builder.dart' show NullabilityBuilder;
+  /// Returns `true` if this builder is an instance member of a class, mixin, or
+  /// extension declaration.
+  ///
+  /// For instance `method1a`, `method2a`, and `method3a` in:
+  ///
+  ///     class A {
+  ///       A.constructor();     // Not a declaration instance member.
+  ///       method1a() {}
+  ///       static method1b() {} // Not a declaration instance member.
+  ///     }
+  ///     mixin B {
+  ///       method2a() {}
+  ///       static method2b() {} // Not a declaration instance member.
+  ///     }
+  ///     extends C on A {
+  ///       method3a() {}
+  ///       static method3b() {} // Not a declaration instance member.
+  ///     }
+  ///
+  bool get isDeclarationInstanceMember;
 
-export 'prefix_builder.dart' show PrefixBuilder;
+  /// Returns `true` if this builder is an instance member of a class or mixin
+  /// extension declaration.
+  ///
+  /// For instance `method1a` and `method2a` in:
+  ///
+  ///     class A {
+  ///       A.constructor();     // Not a class instance member.
+  ///       method1a() {}
+  ///       static method1b() {} // Not a class instance member.
+  ///     }
+  ///     mixin B {
+  ///       method2a() {}
+  ///       static method2b() {} // Not a class instance member.
+  ///     }
+  ///     extends C on A {
+  ///       method3a() {}        // Not a class instance member.
+  ///       static method3b() {} // Not a class instance member.
+  ///     }
+  ///
+  bool get isClassInstanceMember;
 
-export 'type_alias_builder.dart' show TypeAliasBuilder;
+  /// Returns `true` if this builder is an instance member of an extension
+  /// declaration.
+  ///
+  /// For instance `method3a` in:
+  ///
+  ///     class A {
+  ///       A.constructor();     // Not an extension instance member.
+  ///       method1a() {}        // Not an extension instance member.
+  ///       static method1b() {} // Not an extension instance member.
+  ///     }
+  ///     mixin B {
+  ///       method2a() {}        // Not an extension instance member.
+  ///       static method2b() {} // Not an extension instance member.
+  ///     }
+  ///     extends C on A {
+  ///       method3a() {}
+  ///       static method3b() {} // Not an extension instance member.
+  ///     }
+  ///
+  bool get isExtensionInstanceMember;
 
-export 'type_builder.dart' show TypeBuilder;
+  bool get isLocal;
 
-export 'type_declaration_builder.dart' show TypeDeclarationBuilder;
+  bool get isPatch;
 
-export 'type_variable_builder.dart' show TypeVariableBuilder;
+  bool get isRegularMethod;
 
-export 'unresolved_type.dart' show UnresolvedType;
+  bool get isSetter;
 
-export 'void_type_builder.dart' show VoidTypeBuilder;
+  bool get isStatic;
+
+  bool get isSynthetic;
+
+  bool get isTopLevel;
+
+  bool get isTypeDeclaration;
+
+  bool get isTypeVariable;
+
+  /// Applies [patch] to this declaration.
+  void applyPatch(Builder patch);
+
+  /// Returns the number of patches that was finished.
+  int finishPatch();
+
+  /// Resolve constructors (lookup names in scope) recorded in this builder and
+  /// return the number of constructors resolved.
+  int resolveConstructors(covariant Builder parent);
+
+  /// Return `true` if this builder is a duplicate of another with the same
+  /// name. This is `false` for the builder first declared amongst duplicates.
+  bool get isDuplicate;
+}
+
+abstract class BuilderImpl implements Builder {
+  @override
+  Builder next;
+
+  BuilderImpl();
+
+  @override
+  get target => unsupported("${runtimeType}.target", charOffset, fileUri);
+
+  @override
+  Builder get origin => this;
+
+  bool get hasProblem => false;
+
+  @override
+  bool get isConst => false;
+
+  @override
+  bool get isConstructor => false;
+
+  @override
+  bool get isFactory => false;
+
+  @override
+  bool get isField => false;
+
+  @override
+  bool get isFinal => false;
+
+  @override
+  bool get isGetter => false;
+
+  @override
+  bool get isExtension => false;
+
+  @override
+  bool get isDeclarationMember => false;
+
+  @override
+  bool get isClassMember => false;
+
+  @override
+  bool get isExtensionMember => false;
+
+  @override
+  bool get isDeclarationInstanceMember => false;
+
+  @override
+  bool get isClassInstanceMember => false;
+
+  @override
+  bool get isExtensionInstanceMember => false;
+
+  @override
+  bool get isLocal => false;
+
+  @override
+  bool get isPatch => this != origin;
+
+  @override
+  bool get isRegularMethod => false;
+
+  @override
+  bool get isSetter => false;
+
+  @override
+  bool get isStatic => false;
+
+  @override
+  bool get isSynthetic => false;
+
+  @override
+  bool get isTopLevel => false;
+
+  @override
+  bool get isTypeDeclaration => false;
+
+  @override
+  bool get isTypeVariable => false;
+
+  @override
+  void applyPatch(Builder patch) {
+    unsupported("${runtimeType}.applyPatch", charOffset, fileUri);
+  }
+
+  @override
+  int finishPatch() {
+    if (!isPatch) return 0;
+    unsupported("${runtimeType}.finishPatch", charOffset, fileUri);
+    return 0;
+  }
+
+  @override
+  int resolveConstructors(covariant Builder parent) => 0;
+
+  @override
+  bool get isDuplicate => next != null;
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/builtin_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/builtin_type_builder.dart
index cbd6138..277ead6 100644
--- a/pkg/front_end/lib/src/fasta/builder/builtin_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/builtin_type_builder.dart
@@ -6,7 +6,9 @@
 
 import 'package:kernel/ast.dart' show DartType, Nullability;
 
-import 'builder.dart' show LibraryBuilder, NullabilityBuilder, TypeBuilder;
+import 'library_builder.dart';
+import 'nullability_builder.dart';
+import 'type_builder.dart';
 
 import 'type_declaration_builder.dart';
 
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 936a373..262efcd 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -58,23 +58,6 @@
 
 import '../dill/dill_member_builder.dart' show DillMemberBuilder;
 
-import 'builder.dart'
-    show
-        ConstructorReferenceBuilder,
-        Builder,
-        LibraryBuilder,
-        MemberBuilder,
-        MetadataBuilder,
-        NullabilityBuilder,
-        Scope,
-        ScopeBuilder,
-        TypeBuilder,
-        TypeVariableBuilder;
-
-import 'declaration.dart';
-
-import 'declaration_builder.dart';
-
 import '../fasta_codes.dart'
     show
         LocatedMessage,
@@ -112,21 +95,6 @@
         templateRedirectionTargetNotFound,
         templateTypeArgumentMismatch;
 
-import '../kernel/kernel_builder.dart'
-    show
-        ConstructorReferenceBuilder,
-        Builder,
-        FunctionBuilder,
-        NamedTypeBuilder,
-        LibraryBuilder,
-        MemberBuilder,
-        MetadataBuilder,
-        ProcedureBuilder,
-        RedirectingFactoryBuilder,
-        Scope,
-        TypeBuilder,
-        TypeVariableBuilder;
-
 import '../kernel/redirecting_factory_body.dart'
     show getRedirectingFactoryBody, RedirectingFactoryBody;
 
@@ -134,17 +102,32 @@
 
 import '../kernel/types.dart' show Types;
 
+import '../modifier.dart';
+
 import '../names.dart' show noSuchMethodName;
 
 import '../problems.dart'
     show internalProblem, unexpected, unhandled, unimplemented, unsupported;
 
-import '../scope.dart' show AmbiguousBuilder;
+import '../scope.dart';
 
 import '../source/source_library_builder.dart' show SourceLibraryBuilder;
 
 import '../type_inference/type_schema.dart' show UnknownType;
 
+import 'builder.dart';
+import 'constructor_reference_builder.dart';
+import 'declaration_builder.dart';
+import 'function_builder.dart';
+import 'library_builder.dart';
+import 'member_builder.dart';
+import 'metadata_builder.dart';
+import 'named_type_builder.dart';
+import 'nullability_builder.dart';
+import 'procedure_builder.dart';
+import 'type_builder.dart';
+import 'type_variable_builder.dart';
+
 abstract class ClassBuilder implements DeclarationBuilder {
   /// The type variables declared on a class, extension or mixin declaration.
   List<TypeVariableBuilder> typeVariables;
@@ -161,9 +144,9 @@
   /// The types in the `on` clause of an extension or mixin declaration.
   List<TypeBuilder> onTypes;
 
-  Scope get constructors;
+  ConstructorScope get constructors;
 
-  ScopeBuilder get constructorScopeBuilder;
+  ConstructorScopeBuilder get constructorScopeBuilder;
 
   Map<String, ConstructorRedirection> redirectingConstructors;
 
@@ -171,6 +154,16 @@
 
   ClassBuilder patchForTesting;
 
+  bool get isAbstract;
+
+  bool get hasConstConstructor;
+
+  bool get isMixin;
+
+  bool get isMixinApplication;
+
+  bool get isAnonymousMixinApplication;
+
   TypeBuilder get mixedInType;
 
   void set mixedInType(TypeBuilder mixin);
@@ -183,15 +176,11 @@
   /// this redirection gives rise to a cycle that has not been reported before.
   bool checkConstructorCyclic(String source, String target);
 
-  Builder findConstructorOrFactory(
+  MemberBuilder findConstructorOrFactory(
       String name, int charOffset, Uri uri, LibraryBuilder accessingLibrary);
 
   void forEach(void f(String name, Builder builder));
 
-  @override
-  Builder lookupLocalMember(String name,
-      {bool setter: false, bool required: false});
-
   /// Find the first member of this class with [name]. This method isn't
   /// suitable for scope lookups as it will throw an error if the name isn't
   /// declared. The [scope] should be used for that. This method is used to
@@ -216,6 +205,8 @@
 
   Class get actualCls;
 
+  bool isNullClass;
+
   InterfaceType get legacyRawType;
 
   InterfaceType get nullableRawType;
@@ -372,10 +363,10 @@
   List<TypeBuilder> onTypes;
 
   @override
-  final Scope constructors;
+  final ConstructorScope constructors;
 
   @override
-  final ScopeBuilder constructorScopeBuilder;
+  final ConstructorScopeBuilder constructorScopeBuilder;
 
   @override
   Map<String, ConstructorRedirection> redirectingConstructors;
@@ -386,6 +377,9 @@
   @override
   ClassBuilder patchForTesting;
 
+  @override
+  bool isNullClass = false;
+
   ClassBuilderImpl(
       List<MetadataBuilder> metadata,
       int modifiers,
@@ -398,21 +392,33 @@
       this.constructors,
       LibraryBuilder parent,
       int charOffset)
-      : constructorScopeBuilder = new ScopeBuilder(constructors),
+      : constructorScopeBuilder = new ConstructorScopeBuilder(constructors),
         super(metadata, modifiers, name, parent, charOffset, scope);
 
   @override
   String get debugName => "ClassBuilder";
 
   @override
+  bool get isAbstract => (modifiers & abstractMask) != 0;
+
+  bool get isMixin => (modifiers & mixinDeclarationMask) != 0;
+
+  @override
   bool get isMixinApplication => mixedInType != null;
 
   @override
   bool get isNamedMixinApplication {
-    return isMixinApplication && super.isNamedMixinApplication;
+    return isMixinApplication && (modifiers & namedMixinApplicationMask) != 0;
   }
 
   @override
+  bool get isAnonymousMixinApplication {
+    return isMixinApplication && !isNamedMixinApplication;
+  }
+
+  bool get hasConstConstructor => (modifiers & hasConstConstructorMask) != 0;
+
+  @override
   List<ConstructorReferenceBuilder> get constructorReferences => null;
 
   @override
@@ -503,25 +509,21 @@
                 declaration.setRedirectingFactoryBody(
                     targetBuilder.member, typeArguments);
               } else if (targetBuilder is AmbiguousBuilder) {
-                Message message = templateDuplicatedDeclarationUse
-                    .withArguments(redirectionTarget.fullNameForErrors);
-                if (declaration.isConst) {
-                  addProblem(message, declaration.charOffset, noLength);
-                } else {
-                  addProblem(message, declaration.charOffset, noLength);
-                }
+                addProblem(
+                    templateDuplicatedDeclarationUse
+                        .withArguments(redirectionTarget.fullNameForErrors),
+                    redirectionTarget.charOffset,
+                    noLength);
                 // CoreTypes aren't computed yet, and this is the outline
                 // phase. So we can't and shouldn't create a method body.
                 declaration.body = new RedirectingFactoryBody.unresolved(
                     redirectionTarget.fullNameForErrors);
               } else {
-                Message message = templateRedirectionTargetNotFound
-                    .withArguments(redirectionTarget.fullNameForErrors);
-                if (declaration.isConst) {
-                  addProblem(message, declaration.charOffset, noLength);
-                } else {
-                  addProblem(message, declaration.charOffset, noLength);
-                }
+                addProblem(
+                    templateRedirectionTargetNotFound
+                        .withArguments(redirectionTarget.fullNameForErrors),
+                    redirectionTarget.charOffset,
+                    noLength);
                 // CoreTypes aren't computed yet, and this is the outline
                 // phase. So we can't and shouldn't create a method body.
                 declaration.body = new RedirectingFactoryBody.unresolved(
@@ -555,12 +557,12 @@
   }
 
   @override
-  Builder findConstructorOrFactory(
+  MemberBuilder findConstructorOrFactory(
       String name, int charOffset, Uri uri, LibraryBuilder accessingLibrary) {
     if (accessingLibrary.origin != library.origin && name.startsWith("_")) {
       return null;
     }
-    Builder declaration = constructors.lookup(name, charOffset, uri);
+    MemberBuilder declaration = constructors.lookup(name, charOffset, uri);
     if (declaration == null && isPatch) {
       return origin.findConstructorOrFactory(
           name, charOffset, uri, accessingLibrary);
@@ -664,6 +666,9 @@
   InterfaceType buildTypesWithBuiltArguments(LibraryBuilder library,
       Nullability nullability, List<DartType> arguments) {
     assert(arguments == null || cls.typeParameters.length == arguments.length);
+    if (isNullClass) {
+      nullability = Nullability.nullable;
+    }
     return arguments == null
         ? rawType(nullability)
         : new InterfaceType(cls, arguments, nullability);
diff --git a/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
new file mode 100644
index 0000000..bec90c2
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/constructor_builder.dart
@@ -0,0 +1,336 @@
+// 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:core' hide MapEntry;
+
+import 'package:kernel/ast.dart' hide Variance;
+
+import '../../base/common.dart';
+
+import '../../scanner/token.dart' show Token;
+
+import '../constant_context.dart' show ConstantContext;
+
+import '../kernel/body_builder.dart' show BodyBuilder;
+
+import '../kernel/expression_generator_helper.dart'
+    show ExpressionGeneratorHelper;
+
+import '../kernel/kernel_builder.dart'
+    show isRedirectingGenerativeConstructorImplementation;
+
+import '../loader.dart' show Loader;
+
+import '../messages.dart'
+    show
+        Message,
+        messageMoreThanOneSuperOrThisInitializer,
+        messageSuperInitializerNotLast,
+        messageThisInitializerNotAlone,
+        noLength;
+
+import '../source/source_library_builder.dart' show SourceLibraryBuilder;
+
+import 'builder.dart';
+import 'class_builder.dart';
+import 'formal_parameter_builder.dart';
+import 'function_builder.dart';
+import 'library_builder.dart';
+import 'metadata_builder.dart';
+import 'type_builder.dart';
+import 'type_variable_builder.dart';
+
+abstract class ConstructorBuilder implements FunctionBuilder {
+  int get charOpenParenOffset;
+
+  bool hasMovedSuperInitializer;
+
+  SuperInitializer superInitializer;
+
+  RedirectingInitializer redirectingInitializer;
+
+  Token beginInitializers;
+
+  @override
+  ConstructorBuilder get actualOrigin;
+
+  ConstructorBuilder get patchForTesting;
+
+  Constructor get actualConstructor;
+
+  @override
+  ConstructorBuilder get origin;
+
+  bool get isRedirectingGenerativeConstructor;
+
+  bool get isEligibleForTopLevelInference;
+
+  Constructor build(SourceLibraryBuilder libraryBuilder);
+
+  FunctionNode buildFunction(LibraryBuilder library);
+
+  /// The [Constructor] built by this builder.
+  Constructor get constructor;
+
+  void injectInvalidInitializer(
+      Message message, int charOffset, ExpressionGeneratorHelper helper);
+
+  void addInitializer(
+      Initializer initializer, ExpressionGeneratorHelper helper);
+
+  void prepareInitializers();
+}
+
+class ConstructorBuilderImpl extends FunctionBuilderImpl
+    implements ConstructorBuilder {
+  final Constructor _constructor;
+
+  @override
+  final int charOpenParenOffset;
+
+  @override
+  bool hasMovedSuperInitializer = false;
+
+  @override
+  SuperInitializer superInitializer;
+
+  @override
+  RedirectingInitializer redirectingInitializer;
+
+  @override
+  Token beginInitializers;
+
+  @override
+  ConstructorBuilder actualOrigin;
+
+  @override
+  ConstructorBuilder patchForTesting;
+
+  @override
+  Constructor get actualConstructor => _constructor;
+
+  ConstructorBuilderImpl(
+      List<MetadataBuilder> metadata,
+      int modifiers,
+      TypeBuilder returnType,
+      String name,
+      List<TypeVariableBuilder> typeVariables,
+      List<FormalParameterBuilder> formals,
+      SourceLibraryBuilder compilationUnit,
+      int startCharOffset,
+      int charOffset,
+      this.charOpenParenOffset,
+      int charEndOffset,
+      [String nativeMethodName])
+      : _constructor = new Constructor(null, fileUri: compilationUnit?.fileUri)
+          ..startFileOffset = startCharOffset
+          ..fileOffset = charOffset
+          ..fileEndOffset = charEndOffset,
+        super(metadata, modifiers, returnType, name, typeVariables, formals,
+            compilationUnit, charOffset, nativeMethodName);
+
+  @override
+  ConstructorBuilder get origin => actualOrigin ?? this;
+
+  @override
+  bool get isDeclarationInstanceMember => false;
+
+  @override
+  bool get isClassInstanceMember => false;
+
+  @override
+  bool get isConstructor => true;
+
+  @override
+  AsyncMarker get asyncModifier => AsyncMarker.Sync;
+
+  @override
+  ProcedureKind get kind => null;
+
+  @override
+  bool get isRedirectingGenerativeConstructor {
+    return isRedirectingGenerativeConstructorImplementation(_constructor);
+  }
+
+  @override
+  bool get isEligibleForTopLevelInference {
+    if (formals != null) {
+      for (FormalParameterBuilder formal in formals) {
+        if (formal.type == null && formal.isInitializingFormal) return true;
+      }
+    }
+    return false;
+  }
+
+  @override
+  Constructor build(SourceLibraryBuilder libraryBuilder) {
+    if (_constructor.name == null) {
+      _constructor.function = buildFunction(libraryBuilder);
+      _constructor.function.parent = _constructor;
+      _constructor.function.fileOffset = charOpenParenOffset;
+      _constructor.function.fileEndOffset = _constructor.fileEndOffset;
+      _constructor.function.typeParameters = const <TypeParameter>[];
+      _constructor.isConst = isConst;
+      _constructor.isExternal = isExternal;
+      _constructor.name = new Name(name, libraryBuilder.library);
+    }
+    if (isEligibleForTopLevelInference) {
+      for (FormalParameterBuilder formal in formals) {
+        if (formal.type == null && formal.isInitializingFormal) {
+          formal.variable.type = null;
+        }
+      }
+      libraryBuilder.loader.typeInferenceEngine.toBeInferred[_constructor] =
+          libraryBuilder;
+    }
+    return _constructor;
+  }
+
+  @override
+  void buildOutlineExpressions(LibraryBuilder library) {
+    super.buildOutlineExpressions(library);
+
+    // For modular compilation purposes we need to include initializers
+    // for const constructors into the outline.
+    if (isConst && beginInitializers != null) {
+      ClassBuilder classBuilder = parent;
+      BodyBuilder bodyBuilder = library.loader
+          .createBodyBuilderForOutlineExpression(
+              library, classBuilder, this, classBuilder.scope, fileUri);
+      bodyBuilder.constantContext = ConstantContext.required;
+      bodyBuilder.parseInitializers(beginInitializers);
+      bodyBuilder.resolveRedirectingFactoryTargets();
+    }
+    beginInitializers = null;
+  }
+
+  @override
+  FunctionNode buildFunction(LibraryBuilder library) {
+    // According to the specification §9.3 the return type of a constructor
+    // function is its enclosing class.
+    FunctionNode functionNode = super.buildFunction(library);
+    ClassBuilder enclosingClassBuilder = parent;
+    Class enclosingClass = enclosingClassBuilder.cls;
+    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));
+    }
+    functionNode.returnType =
+        new InterfaceType(enclosingClass, typeParameterTypes);
+    return functionNode;
+  }
+
+  @override
+  Constructor get constructor => isPatch ? origin.constructor : _constructor;
+
+  @override
+  Member get member => constructor;
+
+  @override
+  void injectInvalidInitializer(
+      Message message, int charOffset, ExpressionGeneratorHelper helper) {
+    List<Initializer> initializers = _constructor.initializers;
+    Initializer lastInitializer = initializers.removeLast();
+    assert(lastInitializer == superInitializer ||
+        lastInitializer == redirectingInitializer);
+    Initializer error = helper.buildInvalidInitializer(
+        helper.buildProblem(message, charOffset, noLength));
+    initializers.add(error..parent = _constructor);
+    initializers.add(lastInitializer);
+  }
+
+  @override
+  void addInitializer(
+      Initializer initializer, ExpressionGeneratorHelper helper) {
+    List<Initializer> initializers = _constructor.initializers;
+    if (initializer is SuperInitializer) {
+      if (superInitializer != null || redirectingInitializer != null) {
+        injectInvalidInitializer(messageMoreThanOneSuperOrThisInitializer,
+            initializer.fileOffset, helper);
+      } else {
+        initializers.add(initializer..parent = _constructor);
+        superInitializer = initializer;
+      }
+    } else if (initializer is RedirectingInitializer) {
+      if (superInitializer != null || redirectingInitializer != null) {
+        injectInvalidInitializer(messageMoreThanOneSuperOrThisInitializer,
+            initializer.fileOffset, helper);
+      } else if (_constructor.initializers.isNotEmpty) {
+        Initializer first = _constructor.initializers.first;
+        Initializer error = helper.buildInvalidInitializer(helper.buildProblem(
+            messageThisInitializerNotAlone, first.fileOffset, noLength));
+        initializers.add(error..parent = _constructor);
+      } else {
+        initializers.add(initializer..parent = _constructor);
+        redirectingInitializer = initializer;
+      }
+    } else if (redirectingInitializer != null) {
+      injectInvalidInitializer(
+          messageThisInitializerNotAlone, initializer.fileOffset, helper);
+    } else if (superInitializer != null) {
+      injectInvalidInitializer(
+          messageSuperInitializerNotLast, superInitializer.fileOffset, helper);
+    } else {
+      initializers.add(initializer..parent = _constructor);
+    }
+  }
+
+  @override
+  int finishPatch() {
+    if (!isPatch) return 0;
+
+    // TODO(ahe): restore file-offset once we track both origin and patch file
+    // URIs. See https://github.com/dart-lang/sdk/issues/31579
+    origin.constructor.fileUri = fileUri;
+    origin.constructor.startFileOffset = _constructor.startFileOffset;
+    origin.constructor.fileOffset = _constructor.fileOffset;
+    origin.constructor.fileEndOffset = _constructor.fileEndOffset;
+    origin.constructor.annotations
+        .forEach((m) => m.fileOffset = _constructor.fileOffset);
+
+    origin.constructor.isExternal = _constructor.isExternal;
+    origin.constructor.function = _constructor.function;
+    origin.constructor.function.parent = origin.constructor;
+    origin.constructor.initializers = _constructor.initializers;
+    setParents(origin.constructor.initializers, origin.constructor);
+    return 1;
+  }
+
+  @override
+  void becomeNative(Loader loader) {
+    _constructor.isExternal = true;
+    super.becomeNative(loader);
+  }
+
+  @override
+  void applyPatch(Builder patch) {
+    if (patch is ConstructorBuilderImpl) {
+      if (checkPatch(patch)) {
+        patch.actualOrigin = this;
+        if (retainDataForTesting) {
+          patchForTesting = patch;
+        }
+      }
+    } else {
+      reportPatchMismatch(patch);
+    }
+  }
+
+  @override
+  void prepareInitializers() {
+    // For const constructors we parse initializers already at the outlining
+    // stage, there is no easy way to make body building stage skip initializer
+    // parsing, so we simply clear parsed initializers and rebuild them
+    // again.
+    // 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;
+    }
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/constructor_reference_builder.dart b/pkg/front_end/lib/src/fasta/builder/constructor_reference_builder.dart
index d73dd70..f78070e 100644
--- a/pkg/front_end/lib/src/fasta/builder/constructor_reference_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/constructor_reference_builder.dart
@@ -6,16 +6,15 @@
 
 import '../messages.dart' show noLength, templateConstructorNotFound;
 
-import 'builder.dart'
-    show
-        ClassBuilder,
-        Builder,
-        LibraryBuilder,
-        PrefixBuilder,
-        QualifiedName,
-        Scope,
-        TypeBuilder,
-        flattenName;
+import '../identifiers.dart' show QualifiedName, flattenName;
+
+import '../scope.dart';
+
+import 'builder.dart';
+import 'class_builder.dart';
+import 'library_builder.dart';
+import 'prefix_builder.dart';
+import 'type_builder.dart';
 
 class ConstructorReferenceBuilder {
   final int charOffset;
diff --git a/pkg/front_end/lib/src/fasta/builder/declaration.dart b/pkg/front_end/lib/src/fasta/builder/declaration.dart
deleted file mode 100644
index 01043a0..0000000
--- a/pkg/front_end/lib/src/fasta/builder/declaration.dart
+++ /dev/null
@@ -1,327 +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.
-
-library fasta.declaration;
-
-import '../problems.dart' show unsupported;
-
-/// Dummy class to help deprecate [Builder.target].
-abstract class UnrelatedTarget {}
-
-abstract class Builder {
-  /// Used when multiple things with the same name are declared within the same
-  /// parent. Only used for top-level and class-member declarations, not for
-  /// block scopes.
-  Builder next;
-
-  Builder get parent;
-
-  Uri get fileUri;
-
-  int get charOffset;
-
-  get target;
-
-  Builder get origin;
-
-  String get fullNameForErrors;
-
-  bool get hasProblem;
-
-  bool get isConst;
-
-  bool get isConstructor;
-
-  bool get isFactory;
-
-  bool get isField;
-
-  bool get isFinal;
-
-  bool get isGetter;
-
-  /// Returns `true` if this builder is an extension declaration.
-  ///
-  /// For instance `B` in:
-  ///
-  ///    class A {}
-  ///    extension B on A {}
-  ///
-  bool get isExtension;
-
-  /// Returns `true` if this builder is a member of a class, mixin, or extension
-  /// declaration.
-  ///
-  /// For instance `A.constructor`, `method1a`, `method1b`, `method2a`,
-  /// `method2b`, `method3a`, and `method3b` in:
-  ///
-  ///     class A {
-  ///       A.constructor();
-  ///       method1a() {}
-  ///       static method1b() {}
-  ///     }
-  ///     mixin B {
-  ///       method2a() {}
-  ///       static method2b() {}
-  ///     }
-  ///     extends C on A {
-  ///       method3a() {}
-  ///       static method3b() {}
-  ///     }
-  ///
-  bool get isDeclarationMember;
-
-  /// Returns `true` if this builder is a member of a class or mixin
-  /// declaration.
-  ///
-  /// For instance `A.constructor`, `method1a`, `method1b`, `method2a` and
-  /// `method2b` in:
-  ///
-  ///     class A {
-  ///       A.constructor();
-  ///       method1a() {}
-  ///       static method1b() {}
-  ///     }
-  ///     mixin B {
-  ///       method2a() {}
-  ///       static method2b() {}
-  ///     }
-  ///     extends C on A {
-  ///       method3a() {}        // Not a class member.
-  ///       static method3b() {} // Not a class member.
-  ///     }
-  ///
-  bool get isClassMember;
-
-  /// Returns `true` if this builder is a member of an extension declaration.
-  ///
-  /// For instance `method3a` and `method3b` in:
-  ///
-  ///     class A {
-  ///       A.constructor();     // Not an extension member.
-  ///       method1a() {}        // Not an extension member.
-  ///       static method1b() {} // Not an extension member.
-  ///     }
-  ///     mixin B {
-  ///       method2a() {}        // Not an extension member.
-  ///       static method2b() {} // Not an extension member.
-  ///     }
-  ///     extends C on A {
-  ///       method3a() {}
-  ///       static method3b() {}
-  ///     }
-  ///
-  bool get isExtensionMember;
-
-  /// Returns `true` if this builder is an instance member of a class, mixin, or
-  /// extension declaration.
-  ///
-  /// For instance `method1a`, `method2a`, and `method3a` in:
-  ///
-  ///     class A {
-  ///       A.constructor();     // Not a declaration instance member.
-  ///       method1a() {}
-  ///       static method1b() {} // Not a declaration instance member.
-  ///     }
-  ///     mixin B {
-  ///       method2a() {}
-  ///       static method2b() {} // Not a declaration instance member.
-  ///     }
-  ///     extends C on A {
-  ///       method3a() {}
-  ///       static method3b() {} // Not a declaration instance member.
-  ///     }
-  ///
-  bool get isDeclarationInstanceMember;
-
-  /// Returns `true` if this builder is an instance member of a class or mixin
-  /// extension declaration.
-  ///
-  /// For instance `method1a` and `method2a` in:
-  ///
-  ///     class A {
-  ///       A.constructor();     // Not a class instance member.
-  ///       method1a() {}
-  ///       static method1b() {} // Not a class instance member.
-  ///     }
-  ///     mixin B {
-  ///       method2a() {}
-  ///       static method2b() {} // Not a class instance member.
-  ///     }
-  ///     extends C on A {
-  ///       method3a() {}        // Not a class instance member.
-  ///       static method3b() {} // Not a class instance member.
-  ///     }
-  ///
-  bool get isClassInstanceMember;
-
-  /// Returns `true` if this builder is an instance member of an extension
-  /// declaration.
-  ///
-  /// For instance `method3a` in:
-  ///
-  ///     class A {
-  ///       A.constructor();     // Not an extension instance member.
-  ///       method1a() {}        // Not an extension instance member.
-  ///       static method1b() {} // Not an extension instance member.
-  ///     }
-  ///     mixin B {
-  ///       method2a() {}        // Not an extension instance member.
-  ///       static method2b() {} // Not an extension instance member.
-  ///     }
-  ///     extends C on A {
-  ///       method3a() {}
-  ///       static method3b() {} // Not an extension instance member.
-  ///     }
-  ///
-  bool get isExtensionInstanceMember;
-
-  bool get isLocal;
-
-  bool get isPatch;
-
-  bool get isRegularMethod;
-
-  bool get isSetter;
-
-  bool get isStatic;
-
-  bool get isSynthetic;
-
-  bool get isTopLevel;
-
-  bool get isTypeDeclaration;
-
-  bool get isTypeVariable;
-
-  bool get isMixinApplication;
-
-  bool get isNamedMixinApplication;
-
-  bool get isAnonymousMixinApplication;
-
-  /// Applies [patch] to this declaration.
-  void applyPatch(Builder patch);
-
-  /// Returns the number of patches that was finished.
-  int finishPatch();
-
-  /// Resolve constructors (lookup names in scope) recorded in this builder and
-  /// return the number of constructors resolved.
-  int resolveConstructors(covariant Builder parent);
-
-  /// Return `true` if this builder is a duplicate of another with the same
-  /// name. This is `false` for the builder first declared amongst duplicates.
-  bool get isDuplicate;
-}
-
-abstract class BuilderImpl implements Builder {
-  @override
-  Builder next;
-
-  BuilderImpl();
-
-  @override
-  get target => unsupported("${runtimeType}.target", charOffset, fileUri);
-
-  @override
-  Builder get origin => this;
-
-  bool get hasProblem => false;
-
-  @override
-  bool get isConst => false;
-
-  @override
-  bool get isConstructor => false;
-
-  @override
-  bool get isFactory => false;
-
-  @override
-  bool get isField => false;
-
-  @override
-  bool get isFinal => false;
-
-  @override
-  bool get isGetter => false;
-
-  @override
-  bool get isExtension => false;
-
-  @override
-  bool get isDeclarationMember => false;
-
-  @override
-  bool get isClassMember => false;
-
-  @override
-  bool get isExtensionMember => false;
-
-  @override
-  bool get isDeclarationInstanceMember => false;
-
-  @override
-  bool get isClassInstanceMember => false;
-
-  @override
-  bool get isExtensionInstanceMember => false;
-
-  @override
-  bool get isLocal => false;
-
-  @override
-  bool get isPatch => this != origin;
-
-  @override
-  bool get isRegularMethod => false;
-
-  @override
-  bool get isSetter => false;
-
-  @override
-  bool get isStatic => false;
-
-  @override
-  bool get isSynthetic => false;
-
-  @override
-  bool get isTopLevel => false;
-
-  @override
-  bool get isTypeDeclaration => false;
-
-  @override
-  bool get isTypeVariable => false;
-
-  @override
-  bool get isMixinApplication => false;
-
-  @override
-  bool get isNamedMixinApplication => false;
-
-  @override
-  bool get isAnonymousMixinApplication {
-    return isMixinApplication && !isNamedMixinApplication;
-  }
-
-  @override
-  void applyPatch(Builder patch) {
-    unsupported("${runtimeType}.applyPatch", charOffset, fileUri);
-  }
-
-  @override
-  int finishPatch() {
-    if (!isPatch) return 0;
-    unsupported("${runtimeType}.finishPatch", charOffset, fileUri);
-    return 0;
-  }
-
-  @override
-  int resolveConstructors(covariant Builder parent) => 0;
-
-  @override
-  bool get isDuplicate => next != null;
-}
diff --git a/pkg/front_end/lib/src/fasta/builder/dynamic_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/dynamic_type_builder.dart
index b2c03c3..b5c377c 100644
--- a/pkg/front_end/lib/src/fasta/builder/dynamic_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/dynamic_type_builder.dart
@@ -6,7 +6,8 @@
 
 import 'package:kernel/ast.dart' show DartType;
 
-import 'builder.dart' show LibraryBuilder, BuiltinTypeBuilder;
+import 'builtin_type_builder.dart';
+import 'library_builder.dart';
 
 class DynamicTypeBuilder extends BuiltinTypeBuilder {
   DynamicTypeBuilder(
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 ef242db..4cc11c3 100644
--- a/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/enum_builder.dart
@@ -4,8 +4,6 @@
 
 library fasta.enum_builder;
 
-import 'builder.dart' show ClassBuilder, MetadataBuilder, NullabilityBuilder;
-
 import 'package:kernel/ast.dart'
     show
         Arguments,
@@ -36,6 +34,8 @@
         templateDuplicatedDeclarationSyntheticCause,
         templateEnumConstantSameNameAsEnclosing;
 
+import '../kernel/metadata_collector.dart';
+
 import '../modifier.dart'
     show
         constMask,
@@ -44,27 +44,23 @@
         initializingFormalMask,
         staticMask;
 
+import '../scope.dart';
 import '../source/source_class_builder.dart' show SourceClassBuilder;
-
-import '../kernel/kernel_builder.dart'
-    show
-        Builder,
-        FormalParameterBuilder,
-        ClassBuilder,
-        ConstructorBuilder,
-        FieldBuilder,
-        NamedTypeBuilder,
-        ProcedureBuilder,
-        TypeBuilder,
-        LibraryBuilder,
-        MemberBuilder,
-        MetadataBuilder,
-        Scope;
-
-import '../kernel/metadata_collector.dart';
-
 import '../source/source_library_builder.dart' show SourceLibraryBuilder;
 
+import 'builder.dart';
+import 'class_builder.dart';
+import 'constructor_builder.dart';
+import 'field_builder.dart';
+import 'formal_parameter_builder.dart';
+import 'library_builder.dart';
+import 'member_builder.dart';
+import 'metadata_builder.dart';
+import 'named_type_builder.dart';
+import 'nullability_builder.dart';
+import 'procedure_builder.dart';
+import 'type_builder.dart';
+
 class EnumBuilder extends SourceClassBuilder {
   final List<EnumConstantInfo> enumConstantInfos;
 
@@ -80,7 +76,7 @@
       List<MetadataBuilder> metadata,
       String name,
       Scope scope,
-      Scope constructors,
+      ConstructorScope constructors,
       Class cls,
       this.enumConstantInfos,
       this.intType,
@@ -132,11 +128,11 @@
     ///   String toString() => _name;
     /// }
 
-    members["index"] = new FieldBuilder(null, intType, "index",
+    members["index"] = new FieldBuilderImpl(null, intType, "index",
         finalMask | hasInitializerMask, parent, charOffset, charOffset);
-    members["_name"] = new FieldBuilder(null, stringType, "_name",
+    members["_name"] = new FieldBuilderImpl(null, stringType, "_name",
         finalMask | hasInitializerMask, parent, charOffset, charOffset);
-    ConstructorBuilder constructorBuilder = new ConstructorBuilder(
+    ConstructorBuilder constructorBuilder = new ConstructorBuilderImpl(
         null,
         constMask,
         null,
@@ -154,7 +150,7 @@
         charOffset,
         charEndOffset);
     constructors[""] = constructorBuilder;
-    FieldBuilder valuesBuilder = new FieldBuilder(
+    FieldBuilder valuesBuilder = new FieldBuilderImpl(
         null,
         listType,
         "values",
@@ -163,7 +159,7 @@
         charOffset,
         charOffset);
     members["values"] = valuesBuilder;
-    ProcedureBuilder toStringBuilder = new ProcedureBuilder(
+    ProcedureBuilder toStringBuilder = new ProcedureBuilderImpl(
         null,
         0,
         stringType,
@@ -213,7 +209,7 @@
               name.length,
               parent.fileUri);
         }
-        FieldBuilder fieldBuilder = new FieldBuilder(
+        FieldBuilder fieldBuilder = new FieldBuilderImpl(
             metadata,
             selfType,
             name,
@@ -236,7 +232,7 @@
             parent: parent.scope,
             debugName: "enum $name",
             isModifiable: false),
-        new Scope(local: constructors, debugName: name, isModifiable: false),
+        new ConstructorScope(name, constructors),
         cls,
         enumConstantInfos,
         intType,
@@ -352,7 +348,7 @@
   }
 
   @override
-  Builder findConstructorOrFactory(
+  MemberBuilder findConstructorOrFactory(
       String name, int charOffset, Uri uri, LibraryBuilder library) {
     return null;
   }
diff --git a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
index f26fded..3e7daab 100644
--- a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
@@ -9,13 +9,15 @@
 import '../fasta_codes.dart' show templateInternalProblemNotFoundIn;
 import '../scope.dart';
 import '../problems.dart';
+
 import 'builder.dart';
-import 'declaration.dart';
-import 'declaration_builder.dart';
 import 'library_builder.dart';
+import 'member_builder.dart';
 import 'metadata_builder.dart';
+import 'nullability_builder.dart';
 import 'type_builder.dart';
 import 'type_variable_builder.dart';
+import 'declaration_builder.dart';
 
 abstract class ExtensionBuilder implements DeclarationBuilder {
   List<TypeVariableBuilder> get typeParameters;
@@ -30,6 +32,14 @@
   UnrelatedTarget get target;
 
   void buildOutlineExpressions(LibraryBuilder library);
+
+  /// Looks up extension member by [name] taking privacy into account.
+  ///
+  /// If [setter] is `true` the sought member is a setter or assignable field.
+  /// If [required] is `true` and no member is found an internal problem is
+  /// reported.
+  Builder lookupLocalMemberByName(Name name,
+      {bool setter: false, bool required: false});
 }
 
 abstract class ExtensionBuilderImpl extends DeclarationBuilderImpl
@@ -110,6 +120,17 @@
   }
 
   @override
+  Builder lookupLocalMemberByName(Name name,
+      {bool setter: false, bool required: false}) {
+    Builder builder =
+        lookupLocalMember(name.name, setter: setter, required: required);
+    if (builder != null && name.isPrivate && library.library != name.library) {
+      builder = null;
+    }
+    return builder;
+  }
+
+  @override
   String get debugName => "ExtensionBuilder";
 
   @override
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 93fd797..23825f5 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -4,12 +4,6 @@
 
 library fasta.field_builder;
 
-import 'package:kernel/ast.dart' show DartType, Expression;
-
-import 'builder.dart' show LibraryBuilder;
-
-import 'member_builder.dart';
-
 import 'package:kernel/ast.dart'
     show
         Class,
@@ -30,14 +24,9 @@
 
 import '../kernel/body_builder.dart' show BodyBuilder;
 
-import '../kernel/kernel_builder.dart'
-    show
-        ClassBuilder,
-        Builder,
-        ImplicitFieldType,
-        TypeBuilder,
-        LibraryBuilder,
-        MetadataBuilder;
+import '../kernel/kernel_builder.dart' show ImplicitFieldType;
+
+import '../modifier.dart' show covariantMask, hasInitializerMask, lateMask;
 
 import '../problems.dart' show internalProblem;
 
@@ -57,21 +46,62 @@
 
 import '../type_inference/type_schema.dart' show UnknownType;
 
+import 'builder.dart';
+import 'class_builder.dart';
 import 'extension_builder.dart';
+import 'library_builder.dart';
+import 'member_builder.dart';
+import 'metadata_builder.dart';
+import 'type_builder.dart';
 
-class FieldBuilder extends MemberBuilderImpl {
+abstract class FieldBuilder implements MemberBuilder {
+  Field get field;
+
+  List<MetadataBuilder> get metadata;
+
+  TypeBuilder get type;
+
+  Token get constInitializerToken;
+
+  bool hadTypesInferred;
+
+  bool get isCovariant;
+
+  bool get isLate;
+
+  bool get hasInitializer;
+
+  void set initializer(Expression value);
+
+  bool get isEligibleForInference;
+
+  Field build(SourceLibraryBuilder libraryBuilder);
+
+  DartType get builtType;
+}
+
+class FieldBuilderImpl extends MemberBuilderImpl implements FieldBuilder {
+  @override
   final String name;
 
+  @override
   final int modifiers;
 
+  @override
   final Field field;
+
+  @override
   final List<MetadataBuilder> metadata;
+
+  @override
   final TypeBuilder type;
+
+  @override
   Token constInitializerToken;
 
   bool hadTypesInferred = false;
 
-  FieldBuilder(this.metadata, this.type, this.name, this.modifiers,
+  FieldBuilderImpl(this.metadata, this.type, this.name, this.modifiers,
       Builder compilationUnit, int charOffset, int charEndOffset)
       : field = new Field(null, fileUri: compilationUnit?.fileUri)
           ..fileOffset = charOffset
@@ -84,6 +114,15 @@
 
   bool get isField => true;
 
+  @override
+  bool get isLate => (modifiers & lateMask) != 0;
+
+  @override
+  bool get isCovariant => (modifiers & covariantMask) != 0;
+
+  @override
+  bool get hasInitializer => (modifiers & hasInitializerMask) != 0;
+
   void set initializer(Expression value) {
     if (!hasInitializer && value is! NullLiteral && !isConst && !isFinal) {
       internalProblem(
@@ -190,9 +229,9 @@
       return;
     }
     ImplicitFieldType type = field.type;
-    if (type.member != this) {
+    if (type.memberBuilder != this) {
       // The implicit type was inherited.
-      FieldBuilder other = type.member;
+      FieldBuilder other = type.memberBuilder;
       other.inferCopiedType(field);
       return;
     }
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
new file mode 100644
index 0000000..3bbc2f1
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/fixed_type_builder.dart
@@ -0,0 +1,46 @@
+// 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 '../problems.dart';
+import 'library_builder.dart';
+import 'nullability_builder.dart';
+import 'type_builder.dart';
+
+class FixedTypeBuilder extends TypeBuilder {
+  final DartType type;
+
+  const FixedTypeBuilder(this.type);
+
+  TypeBuilder clone(List<TypeBuilder> newTypes) => this;
+
+  Object get name => null;
+
+  NullabilityBuilder get nullabilityBuilder =>
+      new NullabilityBuilder.fromNullability(type.nullability);
+
+  String get debugName => 'FixedTypeBuilder';
+
+  StringBuffer printOn(StringBuffer buffer) {
+    buffer.write('type=${type}');
+    return buffer;
+  }
+
+  DartType build(LibraryBuilder library) => type;
+
+  Supertype buildSupertype(
+      LibraryBuilder library, int charOffset, Uri fileUri) {
+    return unhandled('buildSupertype', 'FixedTypeBuilder', charOffset, fileUri);
+  }
+
+  Supertype buildMixedInType(
+      LibraryBuilder library, int charOffset, Uri fileUri) {
+    return unhandled(
+        'buildMixedInType', 'FixedTypeBuilder', charOffset, fileUri);
+  }
+
+  TypeBuilder withNullabilityBuilder(NullabilityBuilder nullabilityBuilder) =>
+      this;
+}
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 e2f6380..3937dcc 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
@@ -4,6 +4,8 @@
 
 library fasta.formal_parameter_builder;
 
+import 'package:kernel/ast.dart' show VariableDeclaration;
+
 import '../parser.dart' show FormalParameterKind;
 
 import '../parser/formal_parameter_kind.dart'
@@ -12,15 +14,9 @@
         isOptionalNamedFormalParameterKind,
         isOptionalPositionalFormalParameterKind;
 
-import 'builder.dart' show LibraryBuilder, MetadataBuilder, TypeBuilder;
-
-import 'modifier_builder.dart';
-
-import 'package:kernel/ast.dart' show VariableDeclaration;
-
 import '../constant_context.dart' show ConstantContext;
 
-import '../modifier.dart' show finalMask, initializingFormalMask, requiredMask;
+import '../modifier.dart';
 
 import '../scanner.dart' show Token;
 
@@ -32,18 +28,17 @@
 
 import '../kernel/body_builder.dart' show BodyBuilder;
 
-import '../kernel/kernel_builder.dart'
-    show
-        ClassBuilder,
-        Builder,
-        ConstructorBuilder,
-        FieldBuilder,
-        LibraryBuilder,
-        MetadataBuilder,
-        TypeBuilder;
-
 import '../kernel/kernel_shadow_ast.dart' show VariableDeclarationImpl;
 
+import 'builder.dart';
+import 'class_builder.dart';
+import 'constructor_builder.dart';
+import 'field_builder.dart';
+import 'library_builder.dart';
+import 'metadata_builder.dart';
+import 'modifier_builder.dart';
+import 'type_builder.dart';
+
 /// A builder for a formal parameter, i.e. a parameter on a method or
 /// constructor.
 class FormalParameterBuilder extends ModifierBuilderImpl {
@@ -80,6 +75,7 @@
   // named parameters.
   bool get isRequired => isMandatoryFormalParameterKind(kind);
 
+  // TODO(johnniwinther): Rename to `isRequired`.
   bool get isNamedRequired => (modifiers & requiredMask) != 0;
 
   bool get isPositional {
@@ -93,6 +89,10 @@
 
   bool get isLocal => true;
 
+  bool get isInitializingFormal => (modifiers & initializingFormalMask) != 0;
+
+  bool get isCovariant => (modifiers & covariantMask) != 0;
+
   @override
   String get fullNameForErrors => name;
 
diff --git a/pkg/front_end/lib/src/fasta/builder/function_builder.dart b/pkg/front_end/lib/src/fasta/builder/function_builder.dart
new file mode 100644
index 0000000..19ae53c
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/builder/function_builder.dart
@@ -0,0 +1,534 @@
+// 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.
+
+library fasta.procedure_builder;
+
+import 'dart:core' hide MapEntry;
+
+import 'package:front_end/src/fasta/kernel/kernel_api.dart';
+import 'package:kernel/ast.dart' hide Variance;
+
+import 'package:kernel/type_algebra.dart';
+
+import '../scope.dart';
+
+import '../kernel/kernel_shadow_ast.dart' show VariableDeclarationImpl;
+
+import '../kernel/redirecting_factory_body.dart' show RedirectingFactoryBody;
+
+import '../loader.dart' show Loader;
+
+import '../messages.dart'
+    show
+        messageNonInstanceTypeVariableUse,
+        messagePatchDeclarationMismatch,
+        messagePatchDeclarationOrigin,
+        messagePatchNonExternal,
+        noLength;
+
+import '../modifier.dart';
+
+import '../problems.dart' show unexpected;
+
+import '../source/source_library_builder.dart' show SourceLibraryBuilder;
+
+import '../type_inference/type_inference_engine.dart'
+    show IncludesTypeParametersNonCovariantly, Variance;
+
+import 'builder.dart';
+import 'class_builder.dart';
+import 'extension_builder.dart';
+import 'formal_parameter_builder.dart';
+import 'library_builder.dart';
+import 'member_builder.dart';
+import 'metadata_builder.dart';
+import 'type_builder.dart';
+import 'type_variable_builder.dart';
+
+/// Common base class for constructor and procedure builders.
+abstract class FunctionBuilder implements MemberBuilder {
+  List<MetadataBuilder> get metadata;
+
+  TypeBuilder get returnType;
+
+  List<TypeVariableBuilder> get typeVariables;
+
+  List<FormalParameterBuilder> get formals;
+
+  AsyncMarker get asyncModifier;
+
+  ProcedureKind get kind;
+
+  bool get isAbstract;
+
+  bool get isExternal;
+
+  bool get isConstructor;
+
+  bool get isRegularMethod;
+
+  bool get isGetter;
+
+  bool get isSetter;
+
+  bool get isOperator;
+
+  bool get isFactory;
+
+  /// This is the formal parameter scope as specified in the Dart Programming
+  /// Language Specification, 4th ed, section 9.2.
+  Scope computeFormalParameterScope(Scope parent);
+
+  Scope computeFormalParameterInitializerScope(Scope parent);
+
+  /// This scope doesn't correspond to any scope specified in the Dart
+  /// Programming Language Specification, 4th ed. It's an unspecified extension
+  /// to support generic methods.
+  Scope computeTypeParameterScope(Scope parent);
+
+  FormalParameterBuilder getFormal(String name);
+
+  String get nativeMethodName;
+
+  FunctionNode get function;
+
+  FunctionBuilder get actualOrigin;
+
+  Statement get body;
+
+  void set body(Statement newBody);
+
+  void setRedirectingFactoryBody(Member target, List<DartType> typeArguments);
+
+  bool get isNative;
+
+  FunctionNode buildFunction(LibraryBuilder library);
+
+  /// Returns the [index]th parameter of this function.
+  ///
+  /// The index is the syntactical index, including both positional and named
+  /// parameter in the order they are declared, and excluding the synthesized
+  /// this parameter on extension instance members.
+  VariableDeclaration getFormalParameter(int index);
+
+  /// If this is an extension instance method, the tear off closure parameter
+  /// corresponding to the [index]th parameter on the instance method is
+  /// returned.
+  ///
+  /// This is used to update the default value for the closure parameter when
+  /// it has been computed for the original parameter.
+  VariableDeclaration getExtensionTearOffParameter(int index);
+
+  /// Returns the parameter for 'this' synthetically added to extension
+  /// instance members.
+  VariableDeclaration get extensionThis;
+
+  /// Returns a list of synthetic type parameters added to extension instance
+  /// members.
+  List<TypeParameter> get extensionTypeParameters;
+
+  Member build(SourceLibraryBuilder library);
+
+  void becomeNative(Loader loader);
+
+  bool checkPatch(FunctionBuilder patch);
+
+  void reportPatchMismatch(Builder patch);
+}
+
+/// Common base class for constructor and procedure builders.
+abstract class FunctionBuilderImpl extends MemberBuilderImpl
+    implements FunctionBuilder {
+  @override
+  final List<MetadataBuilder> metadata;
+
+  @override
+  final int modifiers;
+
+  @override
+  final TypeBuilder returnType;
+
+  @override
+  final String name;
+
+  @override
+  final List<TypeVariableBuilder> typeVariables;
+
+  @override
+  final List<FormalParameterBuilder> formals;
+
+  /// If this procedure is an extension instance member, [_extensionThis] holds
+  /// the synthetically added `this` parameter.
+  VariableDeclaration _extensionThis;
+
+  /// If this procedure is an extension instance member,
+  /// [_extensionTypeParameters] holds the type parameters copied from the
+  /// extension declaration.
+  List<TypeParameter> _extensionTypeParameters;
+
+  FunctionBuilderImpl(
+      this.metadata,
+      this.modifiers,
+      this.returnType,
+      this.name,
+      this.typeVariables,
+      this.formals,
+      LibraryBuilder compilationUnit,
+      int charOffset,
+      this.nativeMethodName)
+      : super(compilationUnit, charOffset) {
+    if (formals != null) {
+      for (int i = 0; i < formals.length; i++) {
+        formals[i].parent = this;
+      }
+    }
+  }
+
+  @override
+  String get debugName => "FunctionBuilder";
+
+  @override
+  AsyncMarker get asyncModifier;
+
+  @override
+  bool get isConstructor => false;
+
+  @override
+  bool get isAbstract => (modifiers & abstractMask) != 0;
+
+  @override
+  bool get isRegularMethod => identical(ProcedureKind.Method, kind);
+
+  @override
+  bool get isGetter => identical(ProcedureKind.Getter, kind);
+
+  @override
+  bool get isSetter => identical(ProcedureKind.Setter, kind);
+
+  @override
+  bool get isOperator => identical(ProcedureKind.Operator, kind);
+
+  @override
+  bool get isFactory => identical(ProcedureKind.Factory, kind);
+
+  @override
+  bool get isExternal => (modifiers & externalMask) != 0;
+
+  @override
+  Scope computeFormalParameterScope(Scope parent) {
+    if (formals == null) return parent;
+    Map<String, Builder> local = <String, Builder>{};
+    for (FormalParameterBuilder formal in formals) {
+      if (!isConstructor || !formal.isInitializingFormal) {
+        local[formal.name] = formal;
+      }
+    }
+    return new Scope(
+        local: local,
+        parent: parent,
+        debugName: "formal parameter",
+        isModifiable: false);
+  }
+
+  @override
+  Scope computeFormalParameterInitializerScope(Scope parent) {
+    // From
+    // [dartLangSpec.tex](../../../../../../docs/language/dartLangSpec.tex) at
+    // revision 94b23d3b125e9d246e07a2b43b61740759a0dace:
+    //
+    // When the formal parameter list of a non-redirecting generative
+    // constructor contains any initializing formals, a new scope is
+    // introduced, the _formal parameter initializer scope_, which is the
+    // current scope of the initializer list of the constructor, and which is
+    // enclosed in the scope where the constructor is declared.  Each
+    // initializing formal in the formal parameter list introduces a final
+    // local variable into the formal parameter initializer scope, but not into
+    // the formal parameter scope; every other formal parameter introduces a
+    // local variable into both the formal parameter scope and the formal
+    // parameter initializer scope.
+
+    if (formals == null) return parent;
+    Map<String, Builder> local = <String, Builder>{};
+    for (FormalParameterBuilder formal in formals) {
+      local[formal.name] = formal.forFormalParameterInitializerScope();
+    }
+    return new Scope(
+        local: local,
+        parent: parent,
+        debugName: "formal parameter initializer",
+        isModifiable: false);
+  }
+
+  @override
+  Scope computeTypeParameterScope(Scope parent) {
+    if (typeVariables == null) return parent;
+    Map<String, Builder> local = <String, Builder>{};
+    for (TypeVariableBuilder variable in typeVariables) {
+      local[variable.name] = variable;
+    }
+    return new Scope(
+        local: local,
+        parent: parent,
+        debugName: "type parameter",
+        isModifiable: false);
+  }
+
+  @override
+  FormalParameterBuilder getFormal(String name) {
+    if (formals != null) {
+      for (FormalParameterBuilder formal in formals) {
+        if (formal.name == name) return formal;
+      }
+    }
+    return null;
+  }
+
+  @override
+  final String nativeMethodName;
+
+  @override
+  FunctionNode function;
+
+  Statement bodyInternal;
+
+  @override
+  void set body(Statement newBody) {
+//    if (newBody != null) {
+//      if (isAbstract) {
+//        // TODO(danrubel): Is this check needed?
+//        return internalProblem(messageInternalProblemBodyOnAbstractMethod,
+//            newBody.fileOffset, fileUri);
+//      }
+//    }
+    bodyInternal = newBody;
+    if (function != null) {
+      // A forwarding semi-stub is a method that is abstract in the source code,
+      // but which needs to have a forwarding stub body in order to ensure that
+      // covariance checks occur.  We don't want to replace the forwarding stub
+      // body with null.
+      TreeNode parent = function.parent;
+      if (!(newBody == null &&
+          parent is Procedure &&
+          parent.isForwardingSemiStub)) {
+        function.body = newBody;
+        newBody?.parent = function;
+      }
+    }
+  }
+
+  @override
+  void setRedirectingFactoryBody(Member target, List<DartType> typeArguments) {
+    if (bodyInternal != null) {
+      unexpected("null", "${bodyInternal.runtimeType}", charOffset, fileUri);
+    }
+    bodyInternal = new RedirectingFactoryBody(target, typeArguments);
+    function.body = bodyInternal;
+    bodyInternal?.parent = function;
+    if (isPatch) {
+      actualOrigin.setRedirectingFactoryBody(target, typeArguments);
+    }
+  }
+
+  @override
+  Statement get body => bodyInternal ??= new EmptyStatement();
+
+  @override
+  bool get isNative => nativeMethodName != null;
+
+  @override
+  FunctionNode buildFunction(LibraryBuilder library) {
+    assert(function == null);
+    FunctionNode result = new FunctionNode(body, asyncMarker: asyncModifier);
+    IncludesTypeParametersNonCovariantly needsCheckVisitor;
+    if (!isConstructor && !isFactory && parent is ClassBuilder) {
+      ClassBuilder enclosingClassBuilder = parent;
+      Class enclosingClass = enclosingClassBuilder.cls;
+      if (enclosingClass.typeParameters.isNotEmpty) {
+        needsCheckVisitor = new IncludesTypeParametersNonCovariantly(
+            enclosingClass.typeParameters,
+            // We are checking the parameter types which are in a
+            // contravariant position.
+            initialVariance: Variance.contravariant);
+      }
+    }
+    if (typeVariables != null) {
+      for (TypeVariableBuilder t in typeVariables) {
+        TypeParameter parameter = t.parameter;
+        result.typeParameters.add(parameter);
+        if (needsCheckVisitor != null) {
+          if (parameter.bound.accept(needsCheckVisitor)) {
+            parameter.isGenericCovariantImpl = true;
+          }
+        }
+      }
+      setParents(result.typeParameters, result);
+    }
+    if (formals != null) {
+      for (FormalParameterBuilder formal in formals) {
+        VariableDeclaration parameter = formal.build(library, 0);
+        if (needsCheckVisitor != null) {
+          if (parameter.type.accept(needsCheckVisitor)) {
+            parameter.isGenericCovariantImpl = true;
+          }
+        }
+        if (formal.isNamed) {
+          result.namedParameters.add(parameter);
+        } else {
+          result.positionalParameters.add(parameter);
+        }
+        parameter.parent = result;
+        if (formal.isRequired) {
+          result.requiredParameterCount++;
+        }
+      }
+    }
+    if (!isExtensionInstanceMember &&
+        isSetter &&
+        (formals?.length != 1 || formals[0].isOptional)) {
+      // Replace illegal parameters by single dummy parameter.
+      // Do this after building the parameters, since the diet listener
+      // assumes that parameters are built, even if illegal in number.
+      VariableDeclaration parameter =
+          new VariableDeclarationImpl("#synthetic", 0);
+      result.positionalParameters.clear();
+      result.positionalParameters.add(parameter);
+      parameter.parent = result;
+      result.namedParameters.clear();
+      result.requiredParameterCount = 1;
+    }
+    if (returnType != null) {
+      result.returnType = returnType.build(library);
+    }
+    if (!isConstructor &&
+        !isDeclarationInstanceMember &&
+        parent is ClassBuilder) {
+      ClassBuilder enclosingClassBuilder = parent;
+      List<TypeParameter> typeParameters =
+          enclosingClassBuilder.cls.typeParameters;
+      if (typeParameters.isNotEmpty) {
+        Map<TypeParameter, DartType> substitution;
+        DartType removeTypeVariables(DartType type) {
+          if (substitution == null) {
+            substitution = <TypeParameter, DartType>{};
+            for (TypeParameter parameter in typeParameters) {
+              substitution[parameter] = const DynamicType();
+            }
+          }
+          library.addProblem(
+              messageNonInstanceTypeVariableUse, charOffset, noLength, fileUri);
+          return substitute(type, substitution);
+        }
+
+        Set<TypeParameter> set = typeParameters.toSet();
+        for (VariableDeclaration parameter in result.positionalParameters) {
+          if (containsTypeVariable(parameter.type, set)) {
+            parameter.type = removeTypeVariables(parameter.type);
+          }
+        }
+        for (VariableDeclaration parameter in result.namedParameters) {
+          if (containsTypeVariable(parameter.type, set)) {
+            parameter.type = removeTypeVariables(parameter.type);
+          }
+        }
+        if (containsTypeVariable(result.returnType, set)) {
+          result.returnType = removeTypeVariables(result.returnType);
+        }
+      }
+    }
+    if (isExtensionInstanceMember) {
+      ExtensionBuilder extensionBuilder = parent;
+      _extensionThis = result.positionalParameters.first;
+      if (extensionBuilder.typeParameters != null) {
+        int count = extensionBuilder.typeParameters.length;
+        _extensionTypeParameters = new List<TypeParameter>(count);
+        for (int index = 0; index < count; index++) {
+          _extensionTypeParameters[index] = result.typeParameters[index];
+        }
+      }
+    }
+    return function = result;
+  }
+
+  @override
+  VariableDeclaration getFormalParameter(int index) {
+    if (isExtensionInstanceMember) {
+      return formals[index + 1].variable;
+    } else {
+      return formals[index].variable;
+    }
+  }
+
+  @override
+  VariableDeclaration getExtensionTearOffParameter(int index) => null;
+
+  @override
+  VariableDeclaration get extensionThis {
+    assert(_extensionThis != null || !isExtensionInstanceMember,
+        "ProcedureBuilder.extensionThis has not been set.");
+    return _extensionThis;
+  }
+
+  @override
+  List<TypeParameter> get extensionTypeParameters {
+    // Use [_extensionThis] as marker for whether extension type parameters have
+    // been computed.
+    assert(_extensionThis != null || !isExtensionInstanceMember,
+        "ProcedureBuilder.extensionTypeParameters has not been set.");
+    return _extensionTypeParameters;
+  }
+
+  @override
+  void buildOutlineExpressions(LibraryBuilder library) {
+    MetadataBuilder.buildAnnotations(
+        member, metadata, library, isClassMember ? parent : null, this);
+
+    if (formals != null) {
+      // For const constructors we need to include default parameter values
+      // into the outline. For all other formals we need to call
+      // buildOutlineExpressions to clear initializerToken to prevent
+      // consuming too much memory.
+      for (FormalParameterBuilder formal in formals) {
+        formal.buildOutlineExpressions(library);
+      }
+    }
+  }
+
+  @override
+  void becomeNative(Loader loader) {
+    MemberBuilder constructor = loader.getNativeAnnotation();
+    Arguments arguments =
+        new Arguments(<Expression>[new StringLiteral(nativeMethodName)]);
+    Expression annotation;
+    if (constructor.isConstructor) {
+      annotation = new ConstructorInvocation(constructor.member, arguments)
+        ..isConst = true;
+    } else {
+      annotation = new StaticInvocation(constructor.member, arguments)
+        ..isConst = true;
+    }
+    member.addAnnotation(annotation);
+  }
+
+  @override
+  bool checkPatch(FunctionBuilder patch) {
+    if (!isExternal) {
+      patch.library.addProblem(
+          messagePatchNonExternal, patch.charOffset, noLength, patch.fileUri,
+          context: [
+            messagePatchDeclarationOrigin.withLocation(
+                fileUri, charOffset, noLength)
+          ]);
+      return false;
+    }
+    return true;
+  }
+
+  @override
+  void reportPatchMismatch(Builder patch) {
+    library.addProblem(messagePatchDeclarationMismatch, patch.charOffset,
+        noLength, patch.fileUri, context: [
+      messagePatchDeclarationOrigin.withLocation(fileUri, charOffset, noLength)
+    ]);
+  }
+}
diff --git a/pkg/front_end/lib/src/fasta/builder/function_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/function_type_builder.dart
index 2f1777b..dde5a40 100644
--- a/pkg/front_end/lib/src/fasta/builder/function_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/function_type_builder.dart
@@ -4,9 +4,6 @@
 
 library fasta.function_type_builder;
 
-import 'builder.dart'
-    show LibraryBuilder, NullabilityBuilder, TypeBuilder, TypeVariableBuilder;
-
 import 'package:kernel/ast.dart'
     show
         DartType,
@@ -17,17 +14,13 @@
         TypeParameter,
         TypedefType;
 
-import '../fasta_codes.dart'
-    show LocatedMessage, messageSupertypeIsFunction, noLength;
+import '../fasta_codes.dart' show messageSupertypeIsFunction, noLength;
 
-import '../problems.dart' show unsupported;
-
-import '../kernel/kernel_builder.dart'
-    show
-        FormalParameterBuilder,
-        LibraryBuilder,
-        TypeBuilder,
-        TypeVariableBuilder;
+import 'formal_parameter_builder.dart';
+import 'library_builder.dart';
+import 'nullability_builder.dart';
+import 'type_builder.dart';
+import 'type_variable_builder.dart';
 
 class FunctionTypeBuilder extends TypeBuilder {
   final TypeBuilder returnType;
@@ -127,11 +120,6 @@
     return buildSupertype(library, charOffset, fileUri);
   }
 
-  @override
-  buildInvalidType(LocatedMessage message, {List<LocatedMessage> context}) {
-    return unsupported("buildInvalidType", message.charOffset, message.uri);
-  }
-
   FunctionTypeBuilder clone(List<TypeBuilder> newTypes) {
     List<TypeVariableBuilder> clonedTypeVariables;
     if (typeVariables != null) {
diff --git a/pkg/front_end/lib/src/fasta/builder/invalid_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/invalid_type_declaration_builder.dart
similarity index 84%
rename from pkg/front_end/lib/src/fasta/builder/invalid_type_builder.dart
rename to pkg/front_end/lib/src/fasta/builder/invalid_type_declaration_builder.dart
index 58a8d5a..f42b8d4 100644
--- a/pkg/front_end/lib/src/fasta/builder/invalid_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/invalid_type_declaration_builder.dart
@@ -8,13 +8,12 @@
 
 import '../fasta_codes.dart' show LocatedMessage;
 
-import 'builder.dart' show NullabilityBuilder;
-
-import '../kernel/kernel_builder.dart' show TypeBuilder, LibraryBuilder;
-
+import 'library_builder.dart';
+import 'nullability_builder.dart';
+import 'type_builder.dart';
 import 'type_declaration_builder.dart';
 
-class InvalidTypeBuilder extends TypeDeclarationBuilderImpl {
+class InvalidTypeDeclarationBuilder extends TypeDeclarationBuilderImpl {
   String get debugName => "InvalidTypeBuilder";
 
   final LocatedMessage message;
@@ -23,7 +22,7 @@
 
   final bool suppressMessage;
 
-  InvalidTypeBuilder(String name, this.message,
+  InvalidTypeDeclarationBuilder(String name, this.message,
       {this.context, this.suppressMessage: true})
       : super(null, 0, name, null, message.charOffset, message.uri);
 
diff --git a/pkg/front_end/lib/src/fasta/builder/library_builder.dart b/pkg/front_end/lib/src/fasta/builder/library_builder.dart
index 528422f..6d6db2a 100644
--- a/pkg/front_end/lib/src/fasta/builder/library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/library_builder.dart
@@ -25,23 +25,17 @@
 
 import '../severity.dart' show Severity;
 
-import 'builder.dart'
-    show
-        ClassBuilder,
-        Builder,
-        FieldBuilder,
-        MemberBuilder,
-        ModifierBuilder,
-        NameIterator,
-        NullabilityBuilder,
-        PrefixBuilder,
-        Scope,
-        ScopeBuilder,
-        TypeBuilder;
+import '../scope.dart';
 
-import 'declaration.dart';
-
+import 'builder.dart';
+import 'class_builder.dart';
+import 'field_builder.dart';
+import 'member_builder.dart';
 import 'modifier_builder.dart';
+import 'name_iterator.dart';
+import 'nullability_builder.dart';
+import 'prefix_builder.dart';
+import 'type_builder.dart';
 
 abstract class LibraryBuilder implements ModifierBuilder {
   Scope get scope;
@@ -63,7 +57,7 @@
   @override
   UnrelatedTarget get target;
 
-  /// Set the langauge version to a specific non-null major and minor version.
+  /// Set the language version to a specific non-null major and minor version.
   ///
   /// If the language version has previously been explicitly set set (i.e. with
   /// [explicit] set to true), any subsequent call (explicit or not) should be
@@ -231,7 +225,7 @@
       charOffset,
       fileUri);
 
-  /// Set the langauge version to a specific non-null major and minor version.
+  /// Set the language version to a specific non-null major and minor version.
   ///
   /// If the language version has previously been explicitly set set (i.e. with
   /// [explicit] set to true), any subsequent call (explicit or not) should be
@@ -415,10 +409,6 @@
   @override
   List<FieldBuilder> takeImplicitlyTypedFields() => null;
 
-  // TODO(38287): Compute the predicate using the library version instead.
-  @override
-  bool get isNonNullableByDefault => loader.target.enableNonNullable;
-
   @override
   Nullability get nullable {
     return isNonNullableByDefault ? Nullability.nullable : Nullability.legacy;
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 ce8d47f..b17b175 100644
--- a/pkg/front_end/lib/src/fasta/builder/member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
@@ -10,18 +10,16 @@
 
 import '../problems.dart' show unsupported;
 
-import 'builder.dart' show ClassBuilder, Builder, LibraryBuilder;
-
-import 'declaration.dart';
+import 'builder.dart';
+import 'class_builder.dart';
 import 'declaration_builder.dart';
 import 'extension_builder.dart';
+import 'library_builder.dart';
 import 'modifier_builder.dart';
 
 import '../kernel/class_hierarchy_builder.dart';
 
 abstract class MemberBuilder implements ModifierBuilder, ClassMember {
-  bool get isRedirectingGenerativeConstructor;
-
   void set parent(Builder value);
 
   LibraryBuilder get library;
@@ -85,7 +83,6 @@
   @override
   bool get isNative => false;
 
-  @override
   bool get isRedirectingGenerativeConstructor => false;
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/builder/metadata_builder.dart b/pkg/front_end/lib/src/fasta/builder/metadata_builder.dart
index cf5bbb6..2853615 100644
--- a/pkg/front_end/lib/src/fasta/builder/metadata_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/metadata_builder.dart
@@ -8,14 +8,15 @@
 
 import '../kernel/body_builder.dart' show BodyBuilder;
 
-import '../kernel/kernel_builder.dart' show ClassBuilder, MemberBuilder;
-
 import '../scanner.dart' show Token;
 
 import '../source/source_library_builder.dart' show SourceLibraryBuilder;
 
 import '../scope.dart' show Scope;
 
+import 'class_builder.dart';
+import 'member_builder.dart';
+
 class MetadataBuilder {
   final Token beginToken;
 
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 2ecb4a6..a9a572d 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,15 +4,15 @@
 
 library fasta.mixin_application_builder;
 
-import 'builder.dart'
-    show LibraryBuilder, NullabilityBuilder, TypeBuilder, TypeVariableBuilder;
-
 import 'package:kernel/ast.dart' show InterfaceType, Supertype;
 
-import '../fasta_codes.dart' show LocatedMessage;
-
 import '../problems.dart' show unsupported;
 
+import 'library_builder.dart';
+import 'nullability_builder.dart';
+import 'type_builder.dart';
+import 'type_variable_builder.dart';
+
 class MixinApplicationBuilder extends TypeBuilder {
   final TypeBuilder supertype;
   final List<TypeBuilder> mixins;
@@ -62,11 +62,6 @@
   }
 
   @override
-  buildInvalidType(LocatedMessage message, {List<LocatedMessage> context}) {
-    return unsupported("buildInvalidType", message.charOffset, message.uri);
-  }
-
-  @override
   MixinApplicationBuilder withNullabilityBuilder(
       NullabilityBuilder nullabilityBuilder) {
     return unsupported("withNullabilityBuilder", -1, null);
diff --git a/pkg/front_end/lib/src/fasta/builder/modifier_builder.dart b/pkg/front_end/lib/src/fasta/builder/modifier_builder.dart
index 4912129..7820923 100644
--- a/pkg/front_end/lib/src/fasta/builder/modifier_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/modifier_builder.dart
@@ -4,58 +4,22 @@
 
 library fasta.modifier_builder;
 
-import '../modifier.dart'
-    show
-        abstractMask,
-        constMask,
-        covariantMask,
-        externalMask,
-        finalMask,
-        hasConstConstructorMask,
-        hasInitializerMask,
-        initializingFormalMask,
-        lateMask,
-        mixinDeclarationMask,
-        namedMixinApplicationMask,
-        staticMask;
+import '../modifier.dart';
 
-import 'declaration.dart';
+import 'builder.dart';
 
 abstract class ModifierBuilder implements Builder {
-  int get modifiers;
-
-  bool get isAbstract;
-
-  bool get isCovariant;
-
-  bool get isExternal;
-
-  bool get isLate;
-
-  // TODO(johnniwinther): Add this when semantics for
-  // `FormalParameterBuilder.isRequired` has been updated to support required
-  // named parameters.
-  //bool get isRequired;
-
-  bool get hasInitializer;
-
-  bool get isInitializingFormal;
-
-  bool get hasConstConstructor;
-
-  bool get isMixin;
-
   String get name;
 
   bool get isNative;
-
-  String get debugName;
-
-  StringBuffer printOn(StringBuffer buffer);
 }
 
 abstract class ModifierBuilderImpl extends BuilderImpl
     implements ModifierBuilder {
+  int get modifiers;
+
+  String get debugName;
+
   @override
   Builder parent;
 
@@ -69,52 +33,17 @@
       : fileUri = fileUri ?? parent?.fileUri;
 
   @override
-  bool get isAbstract => (modifiers & abstractMask) != 0;
-
-  @override
   bool get isConst => (modifiers & constMask) != 0;
 
   @override
-  bool get isCovariant => (modifiers & covariantMask) != 0;
-
-  @override
-  bool get isExternal => (modifiers & externalMask) != 0;
-
-  @override
   bool get isFinal => (modifiers & finalMask) != 0;
 
   @override
   bool get isStatic => (modifiers & staticMask) != 0;
 
   @override
-  bool get isLate => (modifiers & lateMask) != 0;
-
-  // TODO(johnniwinther): Add this when semantics for
-  // `FormalParameterBuilder.isRequired` has been updated to support required
-  // named parameters.
-  //bool get isRequired => (modifiers & requiredMask) != 0;
-
-  @override
-  bool get isNamedMixinApplication {
-    return (modifiers & namedMixinApplicationMask) != 0;
-  }
-
-  @override
-  bool get hasInitializer => (modifiers & hasInitializerMask) != 0;
-
-  @override
-  bool get isInitializingFormal => (modifiers & initializingFormalMask) != 0;
-
-  @override
-  bool get hasConstConstructor => (modifiers & hasConstConstructorMask) != 0;
-
-  @override
-  bool get isMixin => (modifiers & mixinDeclarationMask) != 0;
-
-  @override
   bool get isNative => false;
 
-  @override
   StringBuffer printOn(StringBuffer buffer) {
     return buffer..write(name ?? fullNameForErrors);
   }
diff --git a/pkg/front_end/lib/src/fasta/builder/name_iterator.dart b/pkg/front_end/lib/src/fasta/builder/name_iterator.dart
index 11303b4..165dfb3 100644
--- a/pkg/front_end/lib/src/fasta/builder/name_iterator.dart
+++ b/pkg/front_end/lib/src/fasta/builder/name_iterator.dart
@@ -4,7 +4,7 @@
 
 library fasta.name_iterator;
 
-import 'builder.dart' show Builder;
+import 'builder.dart';
 
 abstract class NameIterator implements Iterator<Builder> {
   String get name;
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 a956d76..02402c3 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
@@ -19,36 +19,26 @@
         templateTypeArgumentsOnTypeVariable,
         templateTypeNotFound;
 
+import '../identifiers.dart' show Identifier, QualifiedName, flattenName;
+
 import '../messages.dart'
     show noLength, templateSupertypeIsIllegal, templateSupertypeIsTypeVariable;
 
 import '../problems.dart' show unhandled;
 
+import '../scope.dart';
+
 import '../severity.dart' show Severity;
 
-import 'builder.dart'
-    show
-        Builder,
-        Identifier,
-        LibraryBuilder,
-        NullabilityBuilder,
-        PrefixBuilder,
-        QualifiedName,
-        Scope,
-        TypeBuilder,
-        TypeDeclarationBuilder,
-        TypeVariableBuilder,
-        flattenName;
-
-import '../kernel/kernel_builder.dart'
-    show
-        ClassBuilder,
-        InvalidTypeBuilder,
-        LibraryBuilder,
-        TypeBuilder,
-        TypeDeclarationBuilder,
-        TypeVariableBuilder,
-        flattenName;
+import 'builder.dart';
+import 'class_builder.dart';
+import 'invalid_type_declaration_builder.dart';
+import 'library_builder.dart';
+import 'nullability_builder.dart';
+import 'prefix_builder.dart';
+import 'type_builder.dart';
+import 'type_declaration_builder.dart';
+import 'type_variable_builder.dart';
 
 class NamedTypeBuilder extends TypeBuilder {
   final Object name;
@@ -105,7 +95,7 @@
         Message message =
             templateTypeArgumentsOnTypeVariable.withArguments(typeName);
         library.addProblem(message, typeNameOffset, typeName.length, fileUri);
-        declaration = buildInvalidType(
+        declaration = buildInvalidTypeDeclarationBuilder(
             message.withLocation(fileUri, typeNameOffset, typeName.length));
       }
       return;
@@ -146,7 +136,7 @@
         name is Identifier ? name.endCharOffset - charOffset : flatName.length;
     Message message = template.withArguments(flatName);
     library.addProblem(message, charOffset, length, fileUri, context: context);
-    declaration = buildInvalidType(
+    declaration = buildInvalidTypeDeclarationBuilder(
         message.withLocation(fileUri, charOffset, length),
         context: context);
   }
@@ -158,8 +148,8 @@
       Message message = templateTypeArgumentMismatch
           .withArguments(declaration.typeVariablesCount);
       library.addProblem(message, charOffset, noLength, fileUri);
-      declaration =
-          buildInvalidType(message.withLocation(fileUri, charOffset, noLength));
+      declaration = buildInvalidTypeDeclarationBuilder(
+          message.withLocation(fileUri, charOffset, noLength));
     }
   }
 
@@ -189,11 +179,12 @@
     return buffer;
   }
 
-  InvalidTypeBuilder buildInvalidType(LocatedMessage message,
+  InvalidTypeDeclarationBuilder buildInvalidTypeDeclarationBuilder(
+      LocatedMessage message,
       {List<LocatedMessage> context}) {
     // TODO(ahe): Consider if it makes sense to pass a QualifiedName to
     // InvalidTypeBuilder?
-    return new InvalidTypeBuilder(
+    return new InvalidTypeDeclarationBuilder(
         flattenName(name, message.charOffset, message.uri), message,
         context: context);
   }
@@ -222,7 +213,7 @@
     TypeDeclarationBuilder declaration = this.declaration;
     if (declaration is ClassBuilder) {
       return declaration.buildSupertype(library, arguments);
-    } else if (declaration is InvalidTypeBuilder) {
+    } else if (declaration is InvalidTypeDeclarationBuilder) {
       library.addProblem(
           declaration.message.messageObject,
           declaration.message.charOffset,
@@ -240,7 +231,7 @@
     TypeDeclarationBuilder declaration = this.declaration;
     if (declaration is ClassBuilder) {
       return declaration.buildMixedInType(library, arguments);
-    } else if (declaration is InvalidTypeBuilder) {
+    } else if (declaration is InvalidTypeDeclarationBuilder) {
       library.addProblem(
           declaration.message.messageObject,
           declaration.message.charOffset,
diff --git a/pkg/front_end/lib/src/fasta/builder/nullability_builder.dart b/pkg/front_end/lib/src/fasta/builder/nullability_builder.dart
index 3099d95..1fece4a 100644
--- a/pkg/front_end/lib/src/fasta/builder/nullability_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/nullability_builder.dart
@@ -3,11 +3,14 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:core' hide MapEntry;
+
 import 'package:kernel/ast.dart';
+
 import '../kernel/body_builder.dart';
-import '../builder/builder.dart';
 import '../problems.dart';
 
+import 'library_builder.dart';
+
 /// Represents the nullability modifiers encountered while parsing the types.
 ///
 /// The syntactic nullability needs to be interpreted, that is, built, into the
diff --git a/pkg/front_end/lib/src/fasta/builder/prefix_builder.dart b/pkg/front_end/lib/src/fasta/builder/prefix_builder.dart
index 0c63ec4..ffb90bd 100644
--- a/pkg/front_end/lib/src/fasta/builder/prefix_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/prefix_builder.dart
@@ -4,14 +4,15 @@
 
 library fasta.prefix_builder;
 
-import 'builder.dart' show LibraryBuilder, Scope;
-
-import 'declaration.dart';
-
 import 'package:kernel/ast.dart' show LibraryDependency;
 
 import '../kernel/load_library_builder.dart' show LoadLibraryBuilder;
 
+import '../scope.dart';
+
+import 'builder.dart';
+import 'library_builder.dart';
+
 class PrefixBuilder extends BuilderImpl {
   final String name;
 
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 4fd0573..22efa9d 100644
--- a/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
@@ -1,9 +1,7 @@
-// Copyright (c) 2016, 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 fasta.procedure_builder;
-
 import 'dart:core' hide MapEntry;
 
 import 'package:front_end/src/fasta/kernel/kernel_api.dart';
@@ -13,464 +11,73 @@
 
 import '../../base/common.dart';
 
-import 'builder.dart'
-    show
-        Builder,
-        FormalParameterBuilder,
-        LibraryBuilder,
-        MetadataBuilder,
-        Scope,
-        TypeBuilder,
-        TypeVariableBuilder;
-
-import 'member_builder.dart';
-
-import 'extension_builder.dart';
-import 'type_variable_builder.dart';
-
-import '../../scanner/token.dart' show Token;
-
-import '../constant_context.dart' show ConstantContext;
-
-import '../kernel/body_builder.dart' show BodyBuilder;
-
-import '../kernel/expression_generator_helper.dart'
-    show ExpressionGeneratorHelper;
-
-import '../kernel/kernel_builder.dart'
-    show
-        ClassBuilder,
-        ConstructorReferenceBuilder,
-        Builder,
-        FormalParameterBuilder,
-        LibraryBuilder,
-        MetadataBuilder,
-        TypeBuilder,
-        TypeVariableBuilder,
-        isRedirectingGenerativeConstructorImplementation;
-
-import '../kernel/kernel_shadow_ast.dart' show VariableDeclarationImpl;
-
 import '../kernel/redirecting_factory_body.dart' show RedirectingFactoryBody;
 
 import '../loader.dart' show Loader;
 
 import '../messages.dart'
-    show
-        Message,
-        messageConstFactoryRedirectionToNonConst,
-        messageMoreThanOneSuperOrThisInitializer,
-        messageNonInstanceTypeVariableUse,
-        messagePatchDeclarationMismatch,
-        messagePatchDeclarationOrigin,
-        messagePatchNonExternal,
-        messageSuperInitializerNotLast,
-        messageThisInitializerNotAlone,
-        noLength;
+    show messageConstFactoryRedirectionToNonConst, noLength;
 
 import '../problems.dart' show unexpected;
 
 import '../source/source_library_builder.dart' show SourceLibraryBuilder;
 
-import '../type_inference/type_inference_engine.dart'
-    show IncludesTypeParametersNonCovariantly, Variance;
+import 'builder.dart';
+import 'constructor_reference_builder.dart';
+import 'extension_builder.dart';
+import 'formal_parameter_builder.dart';
+import 'function_builder.dart';
+import 'metadata_builder.dart';
+import 'type_builder.dart';
+import 'type_variable_builder.dart';
 
-/// Common base class for constructor and procedure builders.
-abstract class FunctionBuilder extends MemberBuilderImpl {
-  final List<MetadataBuilder> metadata;
+abstract class ProcedureBuilder implements FunctionBuilder {
+  int get charOpenParenOffset;
 
-  final int modifiers;
+  ProcedureBuilder get patchForTesting;
 
-  final TypeBuilder returnType;
+  AsyncMarker actualAsyncModifier;
 
-  final String name;
+  Procedure get actualProcedure;
 
-  final List<TypeVariableBuilder> typeVariables;
-
-  final List<FormalParameterBuilder> formals;
-
-  /// If this procedure is an extension instance member, [_extensionThis] holds
-  /// the synthetically added `this` parameter.
-  VariableDeclaration _extensionThis;
-
-  /// If this procedure is an extension instance member,
-  /// [_extensionTypeParameters] holds the type parameters copied from the
-  /// extension declaration.
-  List<TypeParameter> _extensionTypeParameters;
-
-  FunctionBuilder(
-      this.metadata,
-      this.modifiers,
-      this.returnType,
-      this.name,
-      this.typeVariables,
-      this.formals,
-      LibraryBuilder compilationUnit,
-      int charOffset,
-      this.nativeMethodName)
-      : super(compilationUnit, charOffset) {
-    if (formals != null) {
-      for (int i = 0; i < formals.length; i++) {
-        formals[i].parent = this;
-      }
-    }
-  }
-
-  String get debugName => "FunctionBuilder";
-
-  AsyncMarker get asyncModifier;
-
-  ProcedureKind get kind;
-
-  bool get isConstructor => false;
-
-  bool get isRegularMethod => identical(ProcedureKind.Method, kind);
-
-  bool get isGetter => identical(ProcedureKind.Getter, kind);
-
-  bool get isSetter => identical(ProcedureKind.Setter, kind);
-
-  bool get isOperator => identical(ProcedureKind.Operator, kind);
-
-  bool get isFactory => identical(ProcedureKind.Factory, kind);
-
-  /// This is the formal parameter scope as specified in the Dart Programming
-  /// Language Specification, 4th ed, section 9.2.
-  Scope computeFormalParameterScope(Scope parent) {
-    if (formals == null) return parent;
-    Map<String, Builder> local = <String, Builder>{};
-    for (FormalParameterBuilder formal in formals) {
-      if (!isConstructor || !formal.isInitializingFormal) {
-        local[formal.name] = formal;
-      }
-    }
-    return new Scope(
-        local: local,
-        parent: parent,
-        debugName: "formal parameter",
-        isModifiable: false);
-  }
-
-  Scope computeFormalParameterInitializerScope(Scope parent) {
-    // From
-    // [dartLangSpec.tex](../../../../../../docs/language/dartLangSpec.tex) at
-    // revision 94b23d3b125e9d246e07a2b43b61740759a0dace:
-    //
-    // When the formal parameter list of a non-redirecting generative
-    // constructor contains any initializing formals, a new scope is
-    // introduced, the _formal parameter initializer scope_, which is the
-    // current scope of the initializer list of the constructor, and which is
-    // enclosed in the scope where the constructor is declared.  Each
-    // initializing formal in the formal parameter list introduces a final
-    // local variable into the formal parameter initializer scope, but not into
-    // the formal parameter scope; every other formal parameter introduces a
-    // local variable into both the formal parameter scope and the formal
-    // parameter initializer scope.
-
-    if (formals == null) return parent;
-    Map<String, Builder> local = <String, Builder>{};
-    for (FormalParameterBuilder formal in formals) {
-      local[formal.name] = formal.forFormalParameterInitializerScope();
-    }
-    return new Scope(
-        local: local,
-        parent: parent,
-        debugName: "formal parameter initializer",
-        isModifiable: false);
-  }
-
-  /// This scope doesn't correspond to any scope specified in the Dart
-  /// Programming Language Specification, 4th ed. It's an unspecified extension
-  /// to support generic methods.
-  Scope computeTypeParameterScope(Scope parent) {
-    if (typeVariables == null) return parent;
-    Map<String, Builder> local = <String, Builder>{};
-    for (TypeVariableBuilder variable in typeVariables) {
-      local[variable.name] = variable;
-    }
-    return new Scope(
-        local: local,
-        parent: parent,
-        debugName: "type parameter",
-        isModifiable: false);
-  }
-
-  FormalParameterBuilder getFormal(String name) {
-    if (formals != null) {
-      for (FormalParameterBuilder formal in formals) {
-        if (formal.name == name) return formal;
-      }
-    }
-    return null;
-  }
-
-  final String nativeMethodName;
-
-  FunctionNode function;
-
-  Statement _body;
-
-  FunctionBuilder get actualOrigin;
-
-  void set body(Statement newBody) {
-//    if (newBody != null) {
-//      if (isAbstract) {
-//        // TODO(danrubel): Is this check needed?
-//        return internalProblem(messageInternalProblemBodyOnAbstractMethod,
-//            newBody.fileOffset, fileUri);
-//      }
-//    }
-    _body = newBody;
-    if (function != null) {
-      // A forwarding semi-stub is a method that is abstract in the source code,
-      // but which needs to have a forwarding stub body in order to ensure that
-      // covariance checks occur.  We don't want to replace the forwarding stub
-      // body with null.
-      TreeNode parent = function.parent;
-      if (!(newBody == null &&
-          parent is Procedure &&
-          parent.isForwardingSemiStub)) {
-        function.body = newBody;
-        newBody?.parent = function;
-      }
-    }
-  }
-
-  void setRedirectingFactoryBody(Member target, List<DartType> typeArguments) {
-    if (_body != null) {
-      unexpected("null", "${_body.runtimeType}", charOffset, fileUri);
-    }
-    _body = new RedirectingFactoryBody(target, typeArguments);
-    function.body = _body;
-    _body?.parent = function;
-    if (isPatch) {
-      actualOrigin.setRedirectingFactoryBody(target, typeArguments);
-    }
-  }
-
-  Statement get body => _body ??= new EmptyStatement();
-
-  bool get isNative => nativeMethodName != null;
-
-  FunctionNode buildFunction(LibraryBuilder library) {
-    assert(function == null);
-    FunctionNode result = new FunctionNode(body, asyncMarker: asyncModifier);
-    IncludesTypeParametersNonCovariantly needsCheckVisitor;
-    if (!isConstructor && !isFactory && parent is ClassBuilder) {
-      ClassBuilder enclosingClassBuilder = parent;
-      Class enclosingClass = enclosingClassBuilder.cls;
-      if (enclosingClass.typeParameters.isNotEmpty) {
-        needsCheckVisitor = new IncludesTypeParametersNonCovariantly(
-            enclosingClass.typeParameters,
-            // We are checking the parameter types which are in a
-            // contravariant position.
-            initialVariance: Variance.contravariant);
-      }
-    }
-    if (typeVariables != null) {
-      for (TypeVariableBuilder t in typeVariables) {
-        TypeParameter parameter = t.parameter;
-        result.typeParameters.add(parameter);
-        if (needsCheckVisitor != null) {
-          if (parameter.bound.accept(needsCheckVisitor)) {
-            parameter.isGenericCovariantImpl = true;
-          }
-        }
-      }
-      setParents(result.typeParameters, result);
-    }
-    if (formals != null) {
-      for (FormalParameterBuilder formal in formals) {
-        VariableDeclaration parameter = formal.build(library, 0);
-        if (needsCheckVisitor != null) {
-          if (parameter.type.accept(needsCheckVisitor)) {
-            parameter.isGenericCovariantImpl = true;
-          }
-        }
-        if (formal.isNamed) {
-          result.namedParameters.add(parameter);
-        } else {
-          result.positionalParameters.add(parameter);
-        }
-        parameter.parent = result;
-        if (formal.isRequired) {
-          result.requiredParameterCount++;
-        }
-      }
-    }
-    if (!isExtensionInstanceMember &&
-        isSetter &&
-        (formals?.length != 1 || formals[0].isOptional)) {
-      // Replace illegal parameters by single dummy parameter.
-      // Do this after building the parameters, since the diet listener
-      // assumes that parameters are built, even if illegal in number.
-      VariableDeclaration parameter =
-          new VariableDeclarationImpl("#synthetic", 0);
-      result.positionalParameters.clear();
-      result.positionalParameters.add(parameter);
-      parameter.parent = result;
-      result.namedParameters.clear();
-      result.requiredParameterCount = 1;
-    }
-    if (returnType != null) {
-      result.returnType = returnType.build(library);
-    }
-    if (!isConstructor &&
-        !isDeclarationInstanceMember &&
-        parent is ClassBuilder) {
-      ClassBuilder enclosingClassBuilder = parent;
-      List<TypeParameter> typeParameters =
-          enclosingClassBuilder.cls.typeParameters;
-      if (typeParameters.isNotEmpty) {
-        Map<TypeParameter, DartType> substitution;
-        DartType removeTypeVariables(DartType type) {
-          if (substitution == null) {
-            substitution = <TypeParameter, DartType>{};
-            for (TypeParameter parameter in typeParameters) {
-              substitution[parameter] = const DynamicType();
-            }
-          }
-          library.addProblem(
-              messageNonInstanceTypeVariableUse, charOffset, noLength, fileUri);
-          return substitute(type, substitution);
-        }
-
-        Set<TypeParameter> set = typeParameters.toSet();
-        for (VariableDeclaration parameter in result.positionalParameters) {
-          if (containsTypeVariable(parameter.type, set)) {
-            parameter.type = removeTypeVariables(parameter.type);
-          }
-        }
-        for (VariableDeclaration parameter in result.namedParameters) {
-          if (containsTypeVariable(parameter.type, set)) {
-            parameter.type = removeTypeVariables(parameter.type);
-          }
-        }
-        if (containsTypeVariable(result.returnType, set)) {
-          result.returnType = removeTypeVariables(result.returnType);
-        }
-      }
-    }
-    if (isExtensionInstanceMember) {
-      ExtensionBuilder extensionBuilder = parent;
-      _extensionThis = result.positionalParameters.first;
-      if (extensionBuilder.typeParameters != null) {
-        int count = extensionBuilder.typeParameters.length;
-        _extensionTypeParameters = new List<TypeParameter>(count);
-        for (int index = 0; index < count; index++) {
-          _extensionTypeParameters[index] = result.typeParameters[index];
-        }
-      }
-    }
-    return function = result;
-  }
-
-  /// Returns the [index]th parameter of this function.
-  ///
-  /// The index is the syntactical index, including both positional and named
-  /// parameter in the order they are declared, and excluding the synthesized
-  /// this parameter on extension instance members.
-  VariableDeclaration getFormalParameter(int index) {
-    if (isExtensionInstanceMember) {
-      return formals[index + 1].variable;
-    } else {
-      return formals[index].variable;
-    }
-  }
-
-  /// If this is an extension instance method, the tear off closure parameter
-  /// corresponding to the [index]th parameter on the instance method is
-  /// returned.
-  ///
-  /// This is used to update the default value for the closure parameter when
-  /// it has been computed for the original parameter.
-  VariableDeclaration getExtensionTearOffParameter(int index) => null;
-
-  /// Returns the parameter for 'this' synthetically added to extension
-  /// instance members.
-  VariableDeclaration get extensionThis {
-    assert(_extensionThis != null || !isExtensionInstanceMember,
-        "ProcedureBuilder.extensionThis has not been set.");
-    return _extensionThis;
-  }
-
-  /// Returns a list of synthetic type parameters added to extension instance
-  /// members.
-  List<TypeParameter> get extensionTypeParameters {
-    // Use [_extensionThis] as marker for whether extension type parameters have
-    // been computed.
-    assert(_extensionThis != null || !isExtensionInstanceMember,
-        "ProcedureBuilder.extensionTypeParameters has not been set.");
-    return _extensionTypeParameters;
-  }
-
-  Member build(SourceLibraryBuilder library);
+  bool hadTypesInferred;
 
   @override
-  void buildOutlineExpressions(LibraryBuilder library) {
-    MetadataBuilder.buildAnnotations(
-        member, metadata, library, isClassMember ? parent : null, this);
+  ProcedureBuilder get origin;
 
-    if (formals != null) {
-      // For const constructors we need to include default parameter values
-      // into the outline. For all other formals we need to call
-      // buildOutlineExpressions to clear initializerToken to prevent
-      // consuming too much memory.
-      for (FormalParameterBuilder formal in formals) {
-        formal.buildOutlineExpressions(library);
-      }
-    }
-  }
+  void set asyncModifier(AsyncMarker newModifier);
 
-  void becomeNative(Loader loader) {
-    MemberBuilder constructor = loader.getNativeAnnotation();
-    Arguments arguments =
-        new Arguments(<Expression>[new StringLiteral(nativeMethodName)]);
-    Expression annotation;
-    if (constructor.isConstructor) {
-      annotation = new ConstructorInvocation(constructor.member, arguments)
-        ..isConst = true;
-    } else {
-      annotation = new StaticInvocation(constructor.member, arguments)
-        ..isConst = true;
-    }
-    member.addAnnotation(annotation);
-  }
+  bool get isEligibleForTopLevelInference;
 
-  bool checkPatch(FunctionBuilder patch) {
-    if (!isExternal) {
-      patch.library.addProblem(
-          messagePatchNonExternal, patch.charOffset, noLength, patch.fileUri,
-          context: [
-            messagePatchDeclarationOrigin.withLocation(
-                fileUri, charOffset, noLength)
-          ]);
-      return false;
-    }
-    return true;
-  }
+  /// Returns `true` if this procedure is declared in an extension declaration.
+  bool get isExtensionMethod;
 
-  void reportPatchMismatch(Builder patch) {
-    library.addProblem(messagePatchDeclarationMismatch, patch.charOffset,
-        noLength, patch.fileUri, context: [
-      messagePatchDeclarationOrigin.withLocation(fileUri, charOffset, noLength)
-    ]);
-  }
+  Procedure build(SourceLibraryBuilder libraryBuilder);
 }
 
-class ProcedureBuilder extends FunctionBuilder {
+class ProcedureBuilderImpl extends FunctionBuilderImpl
+    implements ProcedureBuilder {
   final Procedure _procedure;
+
+  @override
   final int charOpenParenOffset;
+
+  @override
   final ProcedureKind kind;
+
+  @override
   ProcedureBuilder patchForTesting;
 
+  @override
   AsyncMarker actualAsyncModifier = AsyncMarker.Sync;
 
   @override
   ProcedureBuilder actualOrigin;
 
+  @override
   Procedure get actualProcedure => _procedure;
 
+  @override
   bool hadTypesInferred = false;
 
   /// If this is an extension instance method then [_extensionTearOff] holds
@@ -485,7 +92,7 @@
   /// these have been built.
   Map<VariableDeclaration, VariableDeclaration> _extensionTearOffParameterMap;
 
-  ProcedureBuilder(
+  ProcedureBuilderImpl(
       List<MetadataBuilder> metadata,
       int modifiers,
       TypeBuilder returnType,
@@ -510,15 +117,18 @@
   @override
   ProcedureBuilder get origin => actualOrigin ?? this;
 
+  @override
   AsyncMarker get asyncModifier => actualAsyncModifier;
 
+  @override
   Statement get body {
-    if (_body == null && !isAbstract && !isExternal) {
-      _body = new EmptyStatement();
+    if (bodyInternal == null && !isAbstract && !isExternal) {
+      bodyInternal = new EmptyStatement();
     }
-    return _body;
+    return bodyInternal;
   }
 
+  @override
   void set asyncModifier(AsyncMarker newModifier) {
     actualAsyncModifier = newModifier;
     if (function != null) {
@@ -528,6 +138,7 @@
     }
   }
 
+  @override
   bool get isEligibleForTopLevelInference {
     if (isDeclarationInstanceMember) {
       if (returnType == null) return true;
@@ -540,11 +151,12 @@
     return false;
   }
 
-  /// Returns `true` if this procedure is declared in an extension declaration.
+  @override
   bool get isExtensionMethod {
     return parent is ExtensionBuilder;
   }
 
+  @override
   Procedure build(SourceLibraryBuilder libraryBuilder) {
     // TODO(ahe): I think we may call this twice on parts. Investigate.
     if (_procedure.name == null) {
@@ -741,11 +353,10 @@
     return null;
   }
 
-  /// The [Procedure] built by this builder.
+  @override
   Procedure get procedure => isPatch ? origin.procedure : _procedure;
 
-  /// If this is an extension instance method then [_extensionTearOff] holds
-  /// the synthetically created tear off function.
+  @override
   Procedure get extensionTearOff {
     if (isExtensionInstanceMember && kind == ProcedureKind.Method) {
       _extensionTearOff ??= new Procedure(null, ProcedureKind.Method, null,
@@ -754,6 +365,7 @@
     return _extensionTearOff;
   }
 
+  @override
   Member get member => procedure;
 
   @override
@@ -784,7 +396,7 @@
 
   @override
   void applyPatch(Builder patch) {
-    if (patch is ProcedureBuilder) {
+    if (patch is ProcedureBuilderImpl) {
       if (checkPatch(patch)) {
         patch.actualOrigin = this;
         if (retainDataForTesting) {
@@ -797,242 +409,7 @@
   }
 }
 
-// TODO(ahe): Move this to own file?
-class ConstructorBuilder extends FunctionBuilder {
-  final Constructor _constructor;
-
-  final int charOpenParenOffset;
-
-  bool hasMovedSuperInitializer = false;
-
-  SuperInitializer superInitializer;
-
-  RedirectingInitializer redirectingInitializer;
-
-  Token beginInitializers;
-
-  @override
-  ConstructorBuilder actualOrigin;
-
-  ConstructorBuilder patchForTesting;
-
-  Constructor get actualConstructor => _constructor;
-
-  ConstructorBuilder(
-      List<MetadataBuilder> metadata,
-      int modifiers,
-      TypeBuilder returnType,
-      String name,
-      List<TypeVariableBuilder> typeVariables,
-      List<FormalParameterBuilder> formals,
-      SourceLibraryBuilder compilationUnit,
-      int startCharOffset,
-      int charOffset,
-      this.charOpenParenOffset,
-      int charEndOffset,
-      [String nativeMethodName])
-      : _constructor = new Constructor(null, fileUri: compilationUnit?.fileUri)
-          ..startFileOffset = startCharOffset
-          ..fileOffset = charOffset
-          ..fileEndOffset = charEndOffset,
-        super(metadata, modifiers, returnType, name, typeVariables, formals,
-            compilationUnit, charOffset, nativeMethodName);
-
-  @override
-  ConstructorBuilder get origin => actualOrigin ?? this;
-
-  @override
-  bool get isDeclarationInstanceMember => false;
-
-  @override
-  bool get isClassInstanceMember => false;
-
-  bool get isConstructor => true;
-
-  AsyncMarker get asyncModifier => AsyncMarker.Sync;
-
-  ProcedureKind get kind => null;
-
-  bool get isRedirectingGenerativeConstructor {
-    return isRedirectingGenerativeConstructorImplementation(_constructor);
-  }
-
-  bool get isEligibleForTopLevelInference {
-    if (formals != null) {
-      for (FormalParameterBuilder formal in formals) {
-        if (formal.type == null && formal.isInitializingFormal) return true;
-      }
-    }
-    return false;
-  }
-
-  Member build(SourceLibraryBuilder libraryBuilder) {
-    if (_constructor.name == null) {
-      _constructor.function = buildFunction(libraryBuilder);
-      _constructor.function.parent = _constructor;
-      _constructor.function.fileOffset = charOpenParenOffset;
-      _constructor.function.fileEndOffset = _constructor.fileEndOffset;
-      _constructor.function.typeParameters = const <TypeParameter>[];
-      _constructor.isConst = isConst;
-      _constructor.isExternal = isExternal;
-      _constructor.name = new Name(name, libraryBuilder.library);
-    }
-    if (isEligibleForTopLevelInference) {
-      for (FormalParameterBuilder formal in formals) {
-        if (formal.type == null && formal.isInitializingFormal) {
-          formal.variable.type = null;
-        }
-      }
-      libraryBuilder.loader.typeInferenceEngine.toBeInferred[_constructor] =
-          libraryBuilder;
-    }
-    return _constructor;
-  }
-
-  @override
-  void buildOutlineExpressions(LibraryBuilder library) {
-    super.buildOutlineExpressions(library);
-
-    // For modular compilation purposes we need to include initializers
-    // for const constructors into the outline.
-    if (isConst && beginInitializers != null) {
-      ClassBuilder classBuilder = parent;
-      BodyBuilder bodyBuilder = library.loader
-          .createBodyBuilderForOutlineExpression(
-              library, classBuilder, this, classBuilder.scope, fileUri);
-      bodyBuilder.constantContext = ConstantContext.required;
-      bodyBuilder.parseInitializers(beginInitializers);
-      bodyBuilder.resolveRedirectingFactoryTargets();
-    }
-    beginInitializers = null;
-  }
-
-  FunctionNode buildFunction(LibraryBuilder library) {
-    // According to the specification §9.3 the return type of a constructor
-    // function is its enclosing class.
-    FunctionNode functionNode = super.buildFunction(library);
-    ClassBuilder enclosingClassBuilder = parent;
-    Class enclosingClass = enclosingClassBuilder.cls;
-    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));
-    }
-    functionNode.returnType =
-        new InterfaceType(enclosingClass, typeParameterTypes);
-    return functionNode;
-  }
-
-  /// The [Constructor] built by this builder.
-  Constructor get constructor => isPatch ? origin.constructor : _constructor;
-
-  Member get member => constructor;
-
-  void injectInvalidInitializer(
-      Message message, int charOffset, ExpressionGeneratorHelper helper) {
-    List<Initializer> initializers = _constructor.initializers;
-    Initializer lastInitializer = initializers.removeLast();
-    assert(lastInitializer == superInitializer ||
-        lastInitializer == redirectingInitializer);
-    Initializer error = helper.buildInvalidInitializer(
-        helper.buildProblem(message, charOffset, noLength));
-    initializers.add(error..parent = _constructor);
-    initializers.add(lastInitializer);
-  }
-
-  void addInitializer(
-      Initializer initializer, ExpressionGeneratorHelper helper) {
-    List<Initializer> initializers = _constructor.initializers;
-    if (initializer is SuperInitializer) {
-      if (superInitializer != null || redirectingInitializer != null) {
-        injectInvalidInitializer(messageMoreThanOneSuperOrThisInitializer,
-            initializer.fileOffset, helper);
-      } else {
-        initializers.add(initializer..parent = _constructor);
-        superInitializer = initializer;
-      }
-    } else if (initializer is RedirectingInitializer) {
-      if (superInitializer != null || redirectingInitializer != null) {
-        injectInvalidInitializer(messageMoreThanOneSuperOrThisInitializer,
-            initializer.fileOffset, helper);
-      } else if (_constructor.initializers.isNotEmpty) {
-        Initializer first = _constructor.initializers.first;
-        Initializer error = helper.buildInvalidInitializer(helper.buildProblem(
-            messageThisInitializerNotAlone, first.fileOffset, noLength));
-        initializers.add(error..parent = _constructor);
-      } else {
-        initializers.add(initializer..parent = _constructor);
-        redirectingInitializer = initializer;
-      }
-    } else if (redirectingInitializer != null) {
-      injectInvalidInitializer(
-          messageThisInitializerNotAlone, initializer.fileOffset, helper);
-    } else if (superInitializer != null) {
-      injectInvalidInitializer(
-          messageSuperInitializerNotLast, superInitializer.fileOffset, helper);
-    } else {
-      initializers.add(initializer..parent = _constructor);
-    }
-  }
-
-  @override
-  int finishPatch() {
-    if (!isPatch) return 0;
-
-    // TODO(ahe): restore file-offset once we track both origin and patch file
-    // URIs. See https://github.com/dart-lang/sdk/issues/31579
-    origin.constructor.fileUri = fileUri;
-    origin.constructor.startFileOffset = _constructor.startFileOffset;
-    origin.constructor.fileOffset = _constructor.fileOffset;
-    origin.constructor.fileEndOffset = _constructor.fileEndOffset;
-    origin.constructor.annotations
-        .forEach((m) => m.fileOffset = _constructor.fileOffset);
-
-    origin.constructor.isExternal = _constructor.isExternal;
-    origin.constructor.function = _constructor.function;
-    origin.constructor.function.parent = origin.constructor;
-    origin.constructor.initializers = _constructor.initializers;
-    setParents(origin.constructor.initializers, origin.constructor);
-    return 1;
-  }
-
-  @override
-  void becomeNative(Loader loader) {
-    _constructor.isExternal = true;
-    super.becomeNative(loader);
-  }
-
-  @override
-  void applyPatch(Builder patch) {
-    if (patch is ConstructorBuilder) {
-      if (checkPatch(patch)) {
-        patch.actualOrigin = this;
-        if (retainDataForTesting) {
-          patchForTesting = patch;
-        }
-      }
-    } else {
-      reportPatchMismatch(patch);
-    }
-  }
-
-  void prepareInitializers() {
-    // For const constructors we parse initializers already at the outlining
-    // stage, there is no easy way to make body building stage skip initializer
-    // parsing, so we simply clear parsed initializers and rebuild them
-    // again.
-    // 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;
-    }
-  }
-}
-
-class RedirectingFactoryBuilder extends ProcedureBuilder {
+class RedirectingFactoryBuilder extends ProcedureBuilderImpl {
   final ConstructorReferenceBuilder redirectionTarget;
   List<DartType> typeArguments;
 
@@ -1066,12 +443,12 @@
             nativeMethodName);
 
   @override
-  Statement get body => _body;
+  Statement get body => bodyInternal;
 
   @override
   void setRedirectingFactoryBody(Member target, List<DartType> typeArguments) {
-    if (_body != null) {
-      unexpected("null", "${_body.runtimeType}", charOffset, fileUri);
+    if (bodyInternal != null) {
+      unexpected("null", "${bodyInternal.runtimeType}", charOffset, fileUri);
     }
 
     // Ensure that constant factories only have constant targets/bodies.
@@ -1080,9 +457,9 @@
           noLength, fileUri);
     }
 
-    _body = new RedirectingFactoryBody(target, typeArguments);
-    function.body = _body;
-    _body?.parent = function;
+    bodyInternal = new RedirectingFactoryBody(target, typeArguments);
+    function.body = bodyInternal;
+    bodyInternal?.parent = function;
     if (isPatch) {
       if (function.typeParameters != null) {
         Map<TypeParameter, DartType> substitution = <TypeParameter, DartType>{};
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 22986a9..ec076a7 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
@@ -21,30 +21,19 @@
 import '../fasta_codes.dart'
     show noLength, templateCyclicTypedef, templateTypeArgumentMismatch;
 
-import '../kernel/kernel_builder.dart'
-    show
-        FunctionTypeBuilder,
-        FormalParameterBuilder,
-        LibraryBuilder,
-        MetadataBuilder,
-        TypeBuilder,
-        TypeVariableBuilder;
-
 import '../problems.dart' show unhandled, unsupported;
 
 import '../source/source_library_builder.dart' show SourceLibraryBuilder;
 
-import 'builder.dart'
-    show
-        LibraryBuilder,
-        MetadataBuilder,
-        NullabilityBuilder,
-        TypeBuilder,
-        TypeVariableBuilder;
-
-import 'declaration.dart';
-
+import 'builder.dart';
+import 'formal_parameter_builder.dart';
+import 'function_type_builder.dart';
+import 'library_builder.dart';
+import 'metadata_builder.dart';
+import 'nullability_builder.dart';
+import 'type_builder.dart';
 import 'type_declaration_builder.dart';
+import 'type_variable_builder.dart';
 
 class TypeAliasBuilder extends TypeDeclarationBuilderImpl {
   final TypeBuilder type;
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 ae2428b..7a8440e 100644
--- a/pkg/front_end/lib/src/fasta/builder/type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/type_builder.dart
@@ -6,8 +6,6 @@
 
 import 'package:kernel/ast.dart' show DartType, Supertype;
 
-import '../fasta_codes.dart' show LocatedMessage;
-
 import '../scope.dart';
 import 'library_builder.dart';
 import 'nullability_builder.dart';
@@ -58,8 +56,6 @@
   /// resolved later.
   TypeBuilder clone(List<TypeBuilder> newTypes);
 
-  buildInvalidType(LocatedMessage message, {List<LocatedMessage> context});
-
   String get fullNameForErrors => "${printOn(new StringBuffer())}";
 
   DartType build(LibraryBuilder library);
diff --git a/pkg/front_end/lib/src/fasta/builder/type_declaration_builder.dart b/pkg/front_end/lib/src/fasta/builder/type_declaration_builder.dart
index a83e29d..bc26462 100644
--- a/pkg/front_end/lib/src/fasta/builder/type_declaration_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/type_declaration_builder.dart
@@ -6,17 +6,16 @@
 
 import 'package:kernel/ast.dart' show DartType, Nullability;
 
-import 'builder.dart'
-    show
-        Builder,
-        LibraryBuilder,
-        MetadataBuilder,
-        NullabilityBuilder,
-        TypeBuilder;
-
+import 'builder.dart';
+import 'library_builder.dart';
+import 'metadata_builder.dart';
 import 'modifier_builder.dart';
+import 'nullability_builder.dart';
+import 'type_builder.dart';
 
 abstract class TypeDeclarationBuilder implements ModifierBuilder {
+  bool get isNamedMixinApplication;
+
   void set parent(Builder value);
 
   List<MetadataBuilder> get metadata;
@@ -49,6 +48,9 @@
         super(parent, charOffset, fileUri);
 
   @override
+  bool get isNamedMixinApplication => false;
+
+  @override
   bool get isTypeDeclaration => true;
 
   @override
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 9021954..f018dfe 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
@@ -4,10 +4,8 @@
 
 library fasta.type_variable_builder;
 
-import 'builder.dart' show LibraryBuilder, NullabilityBuilder, TypeBuilder;
-
 import 'package:kernel/ast.dart'
-    show DartType, Nullability, TypeParameter, TypeParameterType;
+    show DartType, Nullability, TypeParameter, TypeParameterType, Variance;
 
 import '../fasta_codes.dart'
     show
@@ -15,15 +13,16 @@
         templateInternalProblemUnfinishedTypeVariable,
         templateTypeArgumentsOnTypeVariable;
 
-import '../kernel/kernel_builder.dart'
-    show ClassBuilder, NamedTypeBuilder, LibraryBuilder, TypeBuilder;
-
 import '../problems.dart' show unsupported;
 
 import '../source/source_library_builder.dart' show SourceLibraryBuilder;
 
-import 'declaration.dart';
-
+import 'builder.dart';
+import 'class_builder.dart';
+import 'library_builder.dart';
+import 'named_type_builder.dart';
+import 'nullability_builder.dart';
+import 'type_builder.dart';
 import 'type_declaration_builder.dart';
 
 class TypeVariableBuilder extends TypeDeclarationBuilderImpl {
@@ -39,9 +38,12 @@
 
   TypeVariableBuilder(
       String name, SourceLibraryBuilder compilationUnit, int charOffset,
-      {this.bound, this.isExtensionTypeParameter: false})
+      {this.bound,
+      this.isExtensionTypeParameter: false,
+      int variableVariance: Variance.covariant})
       : actualParameter = new TypeParameter(name, null)
-          ..fileOffset = charOffset,
+          ..fileOffset = charOffset
+          ..variance = variableVariance,
         super(null, 0, name, compilationUnit, charOffset);
 
   TypeVariableBuilder.fromKernel(
@@ -236,7 +238,7 @@
     // An alternative is to use the offset of the node the cloned type variable
     // is declared on.
     return new TypeVariableBuilder(name, parent, charOffset,
-        bound: bound.clone(newTypes));
+        bound: bound.clone(newTypes), variableVariance: variance);
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/builder/unresolved_type.dart b/pkg/front_end/lib/src/fasta/builder/unresolved_type.dart
index f80ac6e..4a5ebc4 100644
--- a/pkg/front_end/lib/src/fasta/builder/unresolved_type.dart
+++ b/pkg/front_end/lib/src/fasta/builder/unresolved_type.dart
@@ -4,7 +4,10 @@
 
 library fasta.unresolved_type;
 
-import 'builder.dart' show LibraryBuilder, Scope, TypeBuilder;
+import '../scope.dart';
+
+import 'library_builder.dart';
+import 'type_builder.dart';
 
 /// A wrapper around a type that is yet to be resolved.
 class UnresolvedType {
diff --git a/pkg/front_end/lib/src/fasta/builder/void_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/void_type_builder.dart
index f337f16..9d0478d 100644
--- a/pkg/front_end/lib/src/fasta/builder/void_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/void_type_builder.dart
@@ -6,7 +6,8 @@
 
 import 'package:kernel/ast.dart' show DartType;
 
-import 'builder.dart' show BuiltinTypeBuilder, LibraryBuilder;
+import 'builtin_type_builder.dart';
+import 'library_builder.dart';
 
 class VoidTypeBuilder extends BuiltinTypeBuilder {
   VoidTypeBuilder(DartType type, LibraryBuilder compilationUnit, int charOffset)
diff --git a/pkg/front_end/lib/src/fasta/builder_graph.dart b/pkg/front_end/lib/src/fasta/builder_graph.dart
index 9aa4b18..48cb623 100644
--- a/pkg/front_end/lib/src/fasta/builder_graph.dart
+++ b/pkg/front_end/lib/src/fasta/builder_graph.dart
@@ -8,7 +8,7 @@
 
 import 'package:kernel/util/graph.dart' show Graph;
 
-import 'builder/builder.dart' show LibraryBuilder;
+import 'builder/library_builder.dart';
 
 import 'export.dart' show Export;
 
diff --git a/pkg/front_end/lib/src/fasta/command_line_reporting.dart b/pkg/front_end/lib/src/fasta/command_line_reporting.dart
index 3b00c71..87e21e6 100644
--- a/pkg/front_end/lib/src/fasta/command_line_reporting.dart
+++ b/pkg/front_end/lib/src/fasta/command_line_reporting.dart
@@ -179,9 +179,6 @@
     case Severity.internalProblem:
       return true;
 
-    case Severity.errorLegacyWarning:
-      return true;
-
     case Severity.warning:
     case Severity.context:
       return false;
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart
index 9bd7c59..2afe2b3 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_class_builder.dart
@@ -8,12 +8,15 @@
     show Class, DartType, Member, Supertype, TypeParameter;
 
 import '../builder/class_builder.dart';
+import '../builder/library_builder.dart';
+import '../builder/member_builder.dart';
+import '../builder/type_builder.dart';
+import '../builder/type_variable_builder.dart';
+
+import '../scope.dart';
 
 import '../problems.dart' show unimplemented;
 
-import '../kernel/kernel_builder.dart'
-    show TypeBuilder, LibraryBuilder, MemberBuilder, Scope, TypeVariableBuilder;
-
 import '../modifier.dart' show abstractMask, namedMixinApplicationMask;
 
 import 'dill_library_builder.dart' show DillLibraryBuilder;
@@ -39,10 +42,7 @@
                 parent: parent.scope,
                 debugName: "class ${cls.name}",
                 isModifiable: false),
-            new Scope(
-                local: <String, MemberBuilder>{},
-                debugName: cls.name,
-                isModifiable: false),
+            new ConstructorScope(cls.name, <String, MemberBuilder>{}),
             parent,
             cls.fileOffset);
 
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart
index ff078a1..803ebd2 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_extension_builder.dart
@@ -8,9 +8,10 @@
 
 import '../builder/extension_builder.dart';
 import '../builder/library_builder.dart';
+import '../builder/member_builder.dart';
 import '../builder/type_builder.dart';
 import '../builder/type_variable_builder.dart';
-import '../kernel/kernel_builder.dart';
+
 import '../scope.dart';
 
 import 'dill_class_builder.dart';
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_extension_member_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_extension_member_builder.dart
index d45a8c7..12637f1 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_extension_member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_extension_member_builder.dart
@@ -6,7 +6,7 @@
 
 import 'package:kernel/ast.dart';
 
-import '../builder/declaration.dart';
+import '../builder/builder.dart';
 
 import '../problems.dart';
 
@@ -25,7 +25,6 @@
   @override
   bool get isStatic => _descriptor.isStatic;
 
-  @override
   bool get isExternal => member.isExternal;
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
index 6d5b52d..d13f4d3 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_library_builder.dart
@@ -24,6 +24,14 @@
         StringLiteral,
         Typedef;
 
+import '../builder/builder.dart';
+import '../builder/class_builder.dart';
+import '../builder/dynamic_type_builder.dart';
+import '../builder/invalid_type_declaration_builder.dart';
+import '../builder/library_builder.dart';
+import '../builder/member_builder.dart';
+import '../builder/type_alias_builder.dart';
+
 import '../fasta_codes.dart'
     show
         Message,
@@ -32,20 +40,11 @@
         templateTypeNotFound,
         templateUnspecified;
 
+import '../kernel/redirecting_factory_body.dart' show RedirectingFactoryBody;
+
 import '../problems.dart' show internalProblem, unhandled, unimplemented;
 
-import '../builder/class_builder.dart';
-
-import '../builder/library_builder.dart';
-
-import '../builder/member_builder.dart';
-
-import '../builder/type_alias_builder.dart';
-
-import '../kernel/kernel_builder.dart'
-    show Builder, DynamicTypeBuilder, InvalidTypeBuilder, Scope;
-
-import '../kernel/redirecting_factory_body.dart' show RedirectingFactoryBody;
+import '../scope.dart';
 
 import 'dill_class_builder.dart' show DillClassBuilder;
 
@@ -141,6 +140,9 @@
   bool get isSynthetic => library.isSynthetic;
 
   @override
+  bool get isNonNullableByDefault => library.isNonNullableByDefault;
+
+  @override
   void setLanguageVersion(int major, int minor,
       {int offset: 0, int length, bool explicit}) {}
 
@@ -230,15 +232,15 @@
       String name, Builder builder, Builder other, int charOffset,
       {bool isExport: false, bool isImport: false}) {
     if (builder == other) return builder;
-    if (builder is InvalidTypeBuilder) return builder;
-    if (other is InvalidTypeBuilder) return other;
+    if (builder is InvalidTypeDeclarationBuilder) return builder;
+    if (other is InvalidTypeDeclarationBuilder) return other;
     // For each entry mapping key `k` to declaration `d` in `NS` an entry
     // mapping `k` to `d` is added to the exported namespace of `L` unless a
     // top-level declaration with the name `k` exists in `L`.
     if (builder.parent == this) return builder;
     Message message = templateDuplicatedDeclaration.withArguments(name);
     addProblem(message, charOffset, name.length, fileUri);
-    return new InvalidTypeBuilder(
+    return new InvalidTypeDeclarationBuilder(
         name, message.withLocation(fileUri, charOffset, name.length));
   }
 
@@ -271,7 +273,8 @@
               ? templateTypeNotFound.withArguments(name)
               : templateUnspecified.withArguments(messageText);
           addProblem(message, -1, noLength, null);
-          declaration = new InvalidTypeBuilder(name, message.withoutLocation());
+          declaration = new InvalidTypeDeclarationBuilder(
+              name, message.withoutLocation());
       }
       exportScopeBuilder.addMember(name, declaration);
     });
@@ -294,6 +297,9 @@
       } else if (node is Typedef) {
         libraryUri = node.enclosingLibrary.importUri;
         name = node.name;
+      } else if (node is Extension) {
+        libraryUri = node.enclosingLibrary.importUri;
+        name = node.name;
       } else {
         unhandled("${node.runtimeType}", "finalizeExports", -1, fileUri);
       }
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_loader.dart b/pkg/front_end/lib/src/fasta/dill/dill_loader.dart
index 1a6bbc2..0e2d670 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_loader.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_loader.dart
@@ -8,12 +8,13 @@
 
 import 'package:kernel/ast.dart' show Class, Component, DartType, Library;
 
+import '../builder/class_builder.dart';
+import '../builder/library_builder.dart';
+import '../builder/type_builder.dart';
+
 import '../fasta_codes.dart'
     show SummaryTemplate, Template, templateDillOutlineSummary;
 
-import '../kernel/kernel_builder.dart'
-    show ClassBuilder, TypeBuilder, LibraryBuilder;
-
 import '../kernel/type_builder_computer.dart' show TypeBuilderComputer;
 
 import '../loader.dart' show Loader;
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 3592e37..a6ac789 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
@@ -7,10 +7,11 @@
 import 'package:kernel/ast.dart'
     show Constructor, Field, Member, Procedure, ProcedureKind;
 
+import '../builder/builder.dart';
 import '../builder/member_builder.dart';
 
 import '../kernel/kernel_builder.dart'
-    show Builder, isRedirectingGenerativeConstructorImplementation;
+    show isRedirectingGenerativeConstructorImplementation;
 
 import '../modifier.dart'
     show abstractMask, constMask, externalMask, finalMask, lateMask, staticMask;
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 e9453fe..b79b11a 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_target.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_target.dart
@@ -10,7 +10,7 @@
 
 import 'package:kernel/target/targets.dart' show Target;
 
-import '../kernel/kernel_builder.dart' show ClassBuilder;
+import '../builder/class_builder.dart';
 
 import '../problems.dart' show unsupported;
 
diff --git a/pkg/front_end/lib/src/fasta/dill/dill_type_alias_builder.dart b/pkg/front_end/lib/src/fasta/dill/dill_type_alias_builder.dart
index 42b6dd1..2b3bce9 100644
--- a/pkg/front_end/lib/src/fasta/dill/dill_type_alias_builder.dart
+++ b/pkg/front_end/lib/src/fasta/dill/dill_type_alias_builder.dart
@@ -6,13 +6,11 @@
 
 import 'package:kernel/ast.dart' show DartType, Typedef;
 
-import '../kernel/kernel_builder.dart'
-    show
-        TypeAliasBuilder,
-        FunctionTypeBuilder,
-        TypeBuilder,
-        LibraryBuilder,
-        MetadataBuilder;
+import '../builder/function_type_builder.dart';
+import '../builder/library_builder.dart';
+import '../builder/metadata_builder.dart';
+import '../builder/type_alias_builder.dart';
+import '../builder/type_builder.dart';
 
 import '../problems.dart' show unimplemented;
 
diff --git a/pkg/front_end/lib/src/fasta/export.dart b/pkg/front_end/lib/src/fasta/export.dart
index 05044eb..c0b7bae 100644
--- a/pkg/front_end/lib/src/fasta/export.dart
+++ b/pkg/front_end/lib/src/fasta/export.dart
@@ -4,7 +4,8 @@
 
 library fasta.export;
 
-import 'builder/builder.dart' show Builder, LibraryBuilder;
+import 'builder/builder.dart';
+import 'builder/library_builder.dart';
 
 import 'combinator.dart' show Combinator;
 
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes.dart b/pkg/front_end/lib/src/fasta/fasta_codes.dart
index a0d556e..99f52bd 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes.dart
@@ -64,6 +64,10 @@
   LocatedMessage withoutLocation() {
     return new LocatedMessage(null, -1, noLength, this);
   }
+
+  String toString() {
+    return "Message[$code, $message, $tip, $arguments]";
+  }
 }
 
 class MessageCode extends Code<Null> implements Message {
diff --git a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
index 34eb285..1ad47c1 100644
--- a/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
+++ b/pkg/front_end/lib/src/fasta/fasta_codes_generated.dart
@@ -23,8 +23,7 @@
 const Code<Message Function(String name)> codeAbstractClassInstantiation =
     const Code<Message Function(String name)>(
         "AbstractClassInstantiation", templateAbstractClassInstantiation,
-        analyzerCodes: <String>["NEW_WITH_ABSTRACT_CLASS"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["NEW_WITH_ABSTRACT_CLASS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsAbstractClassInstantiation(String name) {
@@ -70,8 +69,7 @@
     const Code<Message Function(String name)>(
         "AbstractRedirectedClassInstantiation",
         templateAbstractRedirectedClassInstantiation,
-        analyzerCodes: <String>["FACTORY_REDIRECTS_TO_ABSTRACT_CLASS"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["FACTORY_REDIRECTS_TO_ABSTRACT_CLASS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsAbstractRedirectedClassInstantiation(String name) {
@@ -936,29 +934,6 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Template<Message Function(String name)>
-    templateConflictsWithMemberWarning =
-    const Template<Message Function(String name)>(
-        messageTemplate: r"""Conflicts with member '#name'.""",
-        withArguments: _withArgumentsConflictsWithMemberWarning);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Message Function(String name)> codeConflictsWithMemberWarning =
-    const Code<Message Function(String name)>(
-        "ConflictsWithMemberWarning", templateConflictsWithMemberWarning,
-        analyzerCodes: <String>["CONFLICTS_WITH_MEMBER"],
-        severity: Severity.errorLegacyWarning);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-Message _withArgumentsConflictsWithMemberWarning(String name) {
-  if (name.isEmpty) throw 'No name provided';
-  name = demangleMixinApplicationName(name);
-  return new Message(codeConflictsWithMemberWarning,
-      message: """Conflicts with member '${name}'.""",
-      arguments: {'name': name});
-}
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<Message Function(String name)> templateConflictsWithSetter =
     const Template<Message Function(String name)>(
         messageTemplate: r"""Conflicts with setter '#name'.""",
@@ -981,29 +956,6 @@
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Template<Message Function(String name)>
-    templateConflictsWithSetterWarning =
-    const Template<Message Function(String name)>(
-        messageTemplate: r"""Conflicts with setter '#name'.""",
-        withArguments: _withArgumentsConflictsWithSetterWarning);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Message Function(String name)> codeConflictsWithSetterWarning =
-    const Code<Message Function(String name)>(
-        "ConflictsWithSetterWarning", templateConflictsWithSetterWarning,
-        analyzerCodes: <String>["CONFLICTS_WITH_MEMBER"],
-        severity: Severity.errorLegacyWarning);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-Message _withArgumentsConflictsWithSetterWarning(String name) {
-  if (name.isEmpty) throw 'No name provided';
-  name = demangleMixinApplicationName(name);
-  return new Message(codeConflictsWithSetterWarning,
-      message: """Conflicts with setter '${name}'.""",
-      arguments: {'name': name});
-}
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Template<Message Function(String name)>
     templateConflictsWithTypeVariable =
     const Template<Message Function(String name)>(
         messageTemplate: r"""Conflicts with type variable '#name'.""",
@@ -1102,7 +1054,7 @@
     "ConstConstructorWithNonConstSuper",
     analyzerCodes: <String>["CONST_CONSTRUCTOR_WITH_NON_CONST_SUPER"],
     message:
-        r"""Constant constructor can't call non-constant super constructors.""");
+        r"""A constant constructor can't call a non-constant super constructor.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeConstEvalCircularity = messageConstEvalCircularity;
@@ -1826,8 +1778,7 @@
 const Code<Message Function(String name)> codeConstructorNotFound =
     const Code<Message Function(String name)>(
         "ConstructorNotFound", templateConstructorNotFound,
-        analyzerCodes: <String>["CONSTRUCTOR_NOT_FOUND"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["CONSTRUCTOR_NOT_FOUND"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsConstructorNotFound(String name) {
@@ -2112,6 +2063,28 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(String name, String string)>
+    templateDebugTrace =
+    const Template<Message Function(String name, String string)>(
+        messageTemplate: r"""Fatal '#name' at:
+#string""", withArguments: _withArgumentsDebugTrace);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(String name, String string)> codeDebugTrace =
+    const Code<Message Function(String name, String string)>(
+        "DebugTrace", templateDebugTrace,
+        severity: Severity.ignored);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsDebugTrace(String name, String string) {
+  if (name.isEmpty) throw 'No name provided';
+  name = demangleMixinApplicationName(name);
+  if (string.isEmpty) throw 'No string provided';
+  return new Message(codeDebugTrace, message: """Fatal '${name}' at:
+${string}""", arguments: {'name': name, 'string': string});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeDeclaredMemberConflictsWithInheritedMember =
     messageDeclaredMemberConflictsWithInheritedMember;
 
@@ -2239,8 +2212,7 @@
     codeDeferredTypeAnnotation =
     const Code<Message Function(DartType _type, String name)>(
         "DeferredTypeAnnotation", templateDeferredTypeAnnotation,
-        analyzerCodes: <String>["TYPE_ANNOTATION_DEFERRED_CLASS"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["TYPE_ANNOTATION_DEFERRED_CLASS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsDeferredTypeAnnotation(DartType _type, String name) {
@@ -2520,8 +2492,9 @@
 const Code<Message Function(String name, Uri uri_, Uri uri2_)>
     codeDuplicatedExportInType =
     const Code<Message Function(String name, Uri uri_, Uri uri2_)>(
-        "DuplicatedExportInType", templateDuplicatedExportInType,
-        severity: Severity.errorLegacyWarning);
+  "DuplicatedExportInType",
+  templateDuplicatedExportInType,
+);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsDuplicatedExportInType(String name, Uri uri_, Uri uri2_) {
@@ -2573,8 +2546,7 @@
     codeDuplicatedImportInType =
     const Code<Message Function(String name, Uri uri_, Uri uri2_)>(
         "DuplicatedImportInType", templateDuplicatedImportInType,
-        analyzerCodes: <String>["AMBIGUOUS_IMPORT"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["AMBIGUOUS_IMPORT"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsDuplicatedImportInType(String name, Uri uri_, Uri uri2_) {
@@ -3602,6 +3574,29 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Template<Message Function(Token token)>
+    templateExtraneousModifierInExtension =
+    const Template<Message Function(Token token)>(
+        messageTemplate: r"""Can't have modifier '#lexeme' in an extension.""",
+        tipTemplate: r"""Try removing '#lexeme'.""",
+        withArguments: _withArgumentsExtraneousModifierInExtension);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+const Code<Message Function(Token token)> codeExtraneousModifierInExtension =
+    const Code<Message Function(Token token)>(
+        "ExtraneousModifierInExtension", templateExtraneousModifierInExtension,
+        index: 98);
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
+Message _withArgumentsExtraneousModifierInExtension(Token token) {
+  String lexeme = token.lexeme;
+  return new Message(codeExtraneousModifierInExtension,
+      message: """Can't have modifier '${lexeme}' in an extension.""",
+      tip: """Try removing '${lexeme}'.""",
+      arguments: {'token': token});
+}
+
+// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeFactoryNotSync = messageFactoryNotSync;
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -3728,6 +3723,12 @@
     internal stack trace from the compiler. Multiple kinds can be separated by
     commas, for example, --fatal=errors,warnings.
 
+  --fatal-skip=<number>
+  --fatal-skip=trace
+    Skip this many messages that would otherwise be fatal before aborting the
+    compilation. Default is 0, which stops at the first message. Specify
+    'trace' to print a stack trace for every message without stopping.
+
   --enable-experiment=<flag>
     Enable or disable an experimental flag, used to guard features currently
     in development. Prefix an experiment name with 'no-' to disable it.
@@ -4060,62 +4061,6 @@
 }
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Template<
-    Message Function(
-        String name,
-        DartType
-            _type)> templateFfiTypeUnsized = const Template<
-        Message Function(String name, DartType _type)>(
-    messageTemplate:
-        r"""Method '#name' cannot be called on something of type '#type' as this type is unsized.""",
-    withArguments: _withArgumentsFfiTypeUnsized);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Message Function(String name, DartType _type)> codeFfiTypeUnsized =
-    const Code<Message Function(String name, DartType _type)>(
-  "FfiTypeUnsized",
-  templateFfiTypeUnsized,
-);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-Message _withArgumentsFfiTypeUnsized(String name, DartType _type) {
-  if (name.isEmpty) throw 'No name provided';
-  name = demangleMixinApplicationName(name);
-  TypeLabeler labeler = new TypeLabeler();
-  List<Object> typeParts = labeler.labelType(_type);
-  String type = typeParts.join();
-  return new Message(codeFfiTypeUnsized,
-      message:
-          """Method '${name}' cannot be called on something of type '${type}' as this type is unsized.""" +
-              labeler.originMessages,
-      arguments: {'name': name, 'type': _type});
-}
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Template<Message Function(String name)>
-    templateFfiWrongStructInheritance =
-    const Template<Message Function(String name)>(
-        messageTemplate:
-            r"""Struct '#name' must inherit from 'Struct<#name>'.""",
-        withArguments: _withArgumentsFfiWrongStructInheritance);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-const Code<Message Function(String name)> codeFfiWrongStructInheritance =
-    const Code<Message Function(String name)>(
-  "FfiWrongStructInheritance",
-  templateFfiWrongStructInheritance,
-);
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
-Message _withArgumentsFfiWrongStructInheritance(String name) {
-  if (name.isEmpty) throw 'No name provided';
-  name = demangleMixinApplicationName(name);
-  return new Message(codeFfiWrongStructInheritance,
-      message: """Struct '${name}' must inherit from 'Struct<${name}>'.""",
-      arguments: {'name': name});
-}
-
-// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Null> codeFieldInitializedOutsideDeclaringClass =
     messageFieldInitializedOutsideDeclaringClass;
 
@@ -4259,8 +4204,7 @@
     const Code<Message Function(String name)>(
         "FinalInstanceVariableAlreadyInitialized",
         templateFinalInstanceVariableAlreadyInitialized,
-        analyzerCodes: <String>["FINAL_INITIALIZED_MULTIPLE_TIMES"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["FINAL_INITIALIZED_MULTIPLE_TIMES"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsFinalInstanceVariableAlreadyInitialized(String name) {
@@ -4492,8 +4436,7 @@
 const Code<Message Function(String name)> codeGetterNotFound =
     const Code<Message Function(String name)>(
         "GetterNotFound", templateGetterNotFound,
-        analyzerCodes: <String>["UNDEFINED_GETTER"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["UNDEFINED_GETTER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsGetterNotFound(String name) {
@@ -5594,8 +5537,7 @@
     const Code<Message Function(String name, DartType _type, DartType _type2)>(
         "InitializingFormalTypeMismatch",
         templateInitializingFormalTypeMismatch,
-        analyzerCodes: <String>["INVALID_PARAMETER_DECLARATION"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["INVALID_PARAMETER_DECLARATION"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsInitializingFormalTypeMismatch(
@@ -6794,7 +6736,6 @@
 const MessageCode messageListLiteralTooManyTypeArguments = const MessageCode(
     "ListLiteralTooManyTypeArguments",
     analyzerCodes: <String>["EXPECTED_ONE_LIST_TYPE_ARGUMENTS"],
-    severity: Severity.errorLegacyWarning,
     message: r"""List literal requires exactly one type argument.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -6830,7 +6771,6 @@
 const MessageCode messageLoadLibraryTakesNoArguments = const MessageCode(
     "LoadLibraryTakesNoArguments",
     analyzerCodes: <String>["LOAD_LIBRARY_TAKES_NO_ARGUMENTS"],
-    severity: Severity.errorLegacyWarning,
     message: r"""'loadLibrary' takes no arguments.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -6891,7 +6831,6 @@
 const MessageCode messageMapLiteralTypeArgumentMismatch = const MessageCode(
     "MapLiteralTypeArgumentMismatch",
     analyzerCodes: <String>["EXPECTED_TWO_MAP_TYPE_ARGUMENTS"],
-    severity: Severity.errorLegacyWarning,
     message: r"""A map literal requires exactly two type arguments.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -6923,8 +6862,7 @@
 const Code<Message Function(String name)> codeMethodNotFound =
     const Code<Message Function(String name)>(
         "MethodNotFound", templateMethodNotFound,
-        analyzerCodes: <String>["UNDEFINED_METHOD"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["UNDEFINED_METHOD"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsMethodNotFound(String name) {
@@ -7456,8 +7394,7 @@
 const Code<Message Function(String name)> codeNoSuchNamedParameter =
     const Code<Message Function(String name)>(
         "NoSuchNamedParameter", templateNoSuchNamedParameter,
-        analyzerCodes: <String>["UNDEFINED_NAMED_PARAMETER"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["UNDEFINED_NAMED_PARAMETER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsNoSuchNamedParameter(String name) {
@@ -7564,7 +7501,6 @@
 const MessageCode messageNonInstanceTypeVariableUse = const MessageCode(
     "NonInstanceTypeVariableUse",
     analyzerCodes: <String>["TYPE_PARAMETER_REFERENCED_BY_STATIC"],
-    severity: Severity.errorLegacyWarning,
     message: r"""Can only use type variables in instance methods.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -7660,8 +7596,7 @@
     codeNotAPrefixInTypeAnnotation =
     const Code<Message Function(String name, String name2)>(
         "NotAPrefixInTypeAnnotation", templateNotAPrefixInTypeAnnotation,
-        analyzerCodes: <String>["NOT_A_TYPE"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["NOT_A_TYPE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsNotAPrefixInTypeAnnotation(String name, String name2) {
@@ -7684,8 +7619,7 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeNotAType =
     const Code<Message Function(String name)>("NotAType", templateNotAType,
-        analyzerCodes: <String>["NOT_A_TYPE"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["NOT_A_TYPE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsNotAType(String name) {
@@ -7941,8 +7875,7 @@
     codeOverrideFewerNamedArguments =
     const Code<Message Function(String name, String name2)>(
         "OverrideFewerNamedArguments", templateOverrideFewerNamedArguments,
-        analyzerCodes: <String>["INVALID_OVERRIDE_NAMED"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["INVALID_OVERRIDE_NAMED"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsOverrideFewerNamedArguments(String name, String name2) {
@@ -7973,8 +7906,7 @@
     const Code<Message Function(String name, String name2)>(
         "OverrideFewerPositionalArguments",
         templateOverrideFewerPositionalArguments,
-        analyzerCodes: <String>["INVALID_OVERRIDE_POSITIONAL"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["INVALID_OVERRIDE_POSITIONAL"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsOverrideFewerPositionalArguments(
@@ -8007,8 +7939,7 @@
     const Code<Message Function(String name, String name2, String name3)>(
         "OverrideMismatchNamedParameter",
         templateOverrideMismatchNamedParameter,
-        analyzerCodes: <String>["INVALID_OVERRIDE_NAMED"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["INVALID_OVERRIDE_NAMED"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsOverrideMismatchNamedParameter(
@@ -8041,8 +7972,7 @@
     codeOverrideMoreRequiredArguments =
     const Code<Message Function(String name, String name2)>(
         "OverrideMoreRequiredArguments", templateOverrideMoreRequiredArguments,
-        analyzerCodes: <String>["INVALID_OVERRIDE_REQUIRED"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["INVALID_OVERRIDE_REQUIRED"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsOverrideMoreRequiredArguments(String name, String name2) {
@@ -8231,8 +8161,7 @@
     codeOverrideTypeVariablesMismatch =
     const Code<Message Function(String name, String name2)>(
         "OverrideTypeVariablesMismatch", templateOverrideTypeVariablesMismatch,
-        analyzerCodes: <String>["INVALID_METHOD_OVERRIDE_TYPE_PARAMETERS"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["INVALID_METHOD_OVERRIDE_TYPE_PARAMETERS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsOverrideTypeVariablesMismatch(String name, String name2) {
@@ -8372,8 +8301,7 @@
     codePartOfLibraryNameMismatch =
     const Code<Message Function(Uri uri_, String name, String name2)>(
         "PartOfLibraryNameMismatch", templatePartOfLibraryNameMismatch,
-        analyzerCodes: <String>["PART_OF_DIFFERENT_LIBRARY"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["PART_OF_DIFFERENT_LIBRARY"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsPartOfLibraryNameMismatch(
@@ -8444,8 +8372,7 @@
     codePartOfUriMismatch =
     const Code<Message Function(Uri uri_, Uri uri2_, Uri uri3_)>(
         "PartOfUriMismatch", templatePartOfUriMismatch,
-        analyzerCodes: <String>["PART_OF_DIFFERENT_LIBRARY"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["PART_OF_DIFFERENT_LIBRARY"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsPartOfUriMismatch(Uri uri_, Uri uri2_, Uri uri3_) {
@@ -8477,8 +8404,7 @@
     codePartOfUseUri =
     const Code<Message Function(Uri uri_, Uri uri2_, String name)>(
         "PartOfUseUri", templatePartOfUseUri,
-        analyzerCodes: <String>["PART_OF_UNNAMED_LIBRARY"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["PART_OF_UNNAMED_LIBRARY"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsPartOfUseUri(Uri uri_, Uri uri2_, String name) {
@@ -8713,8 +8639,7 @@
 const Code<Message Function(String name)> codeRedirectionTargetNotFound =
     const Code<Message Function(String name)>(
         "RedirectionTargetNotFound", templateRedirectionTargetNotFound,
-        analyzerCodes: <String>["REDIRECT_TO_MISSING_CONSTRUCTOR"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["REDIRECT_TO_MISSING_CONSTRUCTOR"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsRedirectionTargetNotFound(String name) {
@@ -8761,7 +8686,6 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const MessageCode messageReturnTypeFunctionExpression = const MessageCode(
     "ReturnTypeFunctionExpression",
-    severity: Severity.errorLegacyWarning,
     message: r"""A function expression can't have a return type.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -8850,7 +8774,6 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const MessageCode messageSetLiteralTooManyTypeArguments = const MessageCode(
     "SetLiteralTooManyTypeArguments",
-    severity: Severity.errorLegacyWarning,
     message: r"""A set literal requires exactly one type argument.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -8860,7 +8783,6 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const MessageCode messageSetOrMapLiteralTooManyTypeArguments = const MessageCode(
     "SetOrMapLiteralTooManyTypeArguments",
-    severity: Severity.errorLegacyWarning,
     message:
         r"""A set or map literal requires exactly one or two type arguments, respectively.""");
 
@@ -8874,8 +8796,7 @@
 const Code<Message Function(String name)> codeSetterNotFound =
     const Code<Message Function(String name)>(
         "SetterNotFound", templateSetterNotFound,
-        analyzerCodes: <String>["UNDEFINED_SETTER"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["UNDEFINED_SETTER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsSetterNotFound(String name) {
@@ -9276,10 +9197,9 @@
     const Code<Message Function(String name)>(
         "SuperclassHasNoConstructor", templateSuperclassHasNoConstructor,
         analyzerCodes: <String>[
-          "UNDEFINED_CONSTRUCTOR_IN_INITIALIZER",
-          "UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT"
-        ],
-        severity: Severity.errorLegacyWarning);
+      "UNDEFINED_CONSTRUCTOR_IN_INITIALIZER",
+      "UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT"
+    ]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsSuperclassHasNoConstructor(String name) {
@@ -9328,8 +9248,7 @@
 const Code<Message Function(String name)> codeSuperclassHasNoGetter =
     const Code<Message Function(String name)>(
         "SuperclassHasNoGetter", templateSuperclassHasNoGetter,
-        analyzerCodes: <String>["UNDEFINED_SUPER_GETTER"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["UNDEFINED_SUPER_GETTER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsSuperclassHasNoGetter(String name) {
@@ -9350,8 +9269,7 @@
 const Code<Message Function(String name)> codeSuperclassHasNoMethod =
     const Code<Message Function(String name)>(
         "SuperclassHasNoMethod", templateSuperclassHasNoMethod,
-        analyzerCodes: <String>["UNDEFINED_SUPER_METHOD"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["UNDEFINED_SUPER_METHOD"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsSuperclassHasNoMethod(String name) {
@@ -9372,8 +9290,7 @@
 const Code<Message Function(String name)> codeSuperclassHasNoSetter =
     const Code<Message Function(String name)>(
         "SuperclassHasNoSetter", templateSuperclassHasNoSetter,
-        analyzerCodes: <String>["UNDEFINED_SUPER_SETTER"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["UNDEFINED_SUPER_SETTER"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsSuperclassHasNoSetter(String name) {
@@ -9397,9 +9314,9 @@
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 const Code<Message Function(String name)> codeSuperclassMethodArgumentMismatch =
     const Code<Message Function(String name)>(
-        "SuperclassMethodArgumentMismatch",
-        templateSuperclassMethodArgumentMismatch,
-        severity: Severity.errorLegacyWarning);
+  "SuperclassMethodArgumentMismatch",
+  templateSuperclassMethodArgumentMismatch,
+);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsSuperclassMethodArgumentMismatch(String name) {
@@ -9469,7 +9386,6 @@
 const MessageCode messageSwitchCaseFallThrough = const MessageCode(
     "SwitchCaseFallThrough",
     analyzerCodes: <String>["CASE_BLOCK_NOT_TERMINATED"],
-    severity: Severity.errorLegacyWarning,
     message: r"""Switch case may fall through to the next case.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -9625,8 +9541,7 @@
 const Code<Message Function(int count, int count2)> codeTooFewArguments =
     const Code<Message Function(int count, int count2)>(
         "TooFewArguments", templateTooFewArguments,
-        analyzerCodes: <String>["NOT_ENOUGH_REQUIRED_ARGUMENTS"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["NOT_ENOUGH_REQUIRED_ARGUMENTS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsTooFewArguments(int count, int count2) {
@@ -9654,8 +9569,7 @@
 const Code<Message Function(int count, int count2)> codeTooManyArguments =
     const Code<Message Function(int count, int count2)>(
         "TooManyArguments", templateTooManyArguments,
-        analyzerCodes: <String>["EXTRA_POSITIONAL_ARGUMENTS"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["EXTRA_POSITIONAL_ARGUMENTS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsTooManyArguments(int count, int count2) {
@@ -9699,8 +9613,7 @@
 const Code<Message Function(int count)> codeTypeArgumentMismatch =
     const Code<Message Function(int count)>(
         "TypeArgumentMismatch", templateTypeArgumentMismatch,
-        analyzerCodes: <String>["WRONG_NUMBER_OF_TYPE_ARGUMENTS"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["WRONG_NUMBER_OF_TYPE_ARGUMENTS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsTypeArgumentMismatch(int count) {
@@ -9723,7 +9636,7 @@
 const Code<Message Function(String name)> codeTypeArgumentsOnTypeVariable =
     const Code<Message Function(String name)>(
         "TypeArgumentsOnTypeVariable", templateTypeArgumentsOnTypeVariable,
-        index: 13, severity: Severity.errorLegacyWarning);
+        index: 13);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsTypeArgumentsOnTypeVariable(String name) {
@@ -9755,8 +9668,7 @@
 const Code<Message Function(String name)> codeTypeNotFound =
     const Code<Message Function(String name)>(
         "TypeNotFound", templateTypeNotFound,
-        analyzerCodes: <String>["UNDEFINED_CLASS"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["UNDEFINED_CLASS"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsTypeNotFound(String name) {
@@ -9865,7 +9777,6 @@
 const MessageCode messageTypeVariableInStaticContext = const MessageCode(
     "TypeVariableInStaticContext",
     analyzerCodes: <String>["TYPE_PARAMETER_REFERENCED_BY_STATIC"],
-    severity: Severity.errorLegacyWarning,
     message: r"""Type variables can't be used in static members.""");
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
@@ -10072,8 +9983,7 @@
     const Code<Message Function(String name, String name2)>(
         "UnresolvedPrefixInTypeAnnotation",
         templateUnresolvedPrefixInTypeAnnotation,
-        analyzerCodes: <String>["NOT_A_TYPE"],
-        severity: Severity.errorLegacyWarning);
+        analyzerCodes: <String>["NOT_A_TYPE"]);
 
 // DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
 Message _withArgumentsUnresolvedPrefixInTypeAnnotation(
diff --git a/pkg/front_end/lib/src/fasta/flow_analysis/flow_analysis.dart b/pkg/front_end/lib/src/fasta/flow_analysis/flow_analysis.dart
index a2b1c4d..7129694 100644
--- a/pkg/front_end/lib/src/fasta/flow_analysis/flow_analysis.dart
+++ b/pkg/front_end/lib/src/fasta/flow_analysis/flow_analysis.dart
@@ -33,31 +33,43 @@
   /// write is captured by a local function or closure inside that node.
   final Map<Node, Set<Variable>> _capturedInNode = {};
 
+  /// Set of local variables that are potentially written to anywhere in the
+  /// code being analyzed.
+  final Set<Variable> _writtenAnywhere = {};
+
+  /// Set of local variables for which a potential write is captured by a local
+  /// function or closure anywhere in the code being analyzed.
+  final Set<Variable> _capturedAnywhere = {};
+
   /// Stack of sets accumulating variables that are potentially written to.
   ///
   /// A set is pushed onto the stack when a node is entered, and popped when
   /// a node is left.
-  final List<Set<Variable>> _writtenStack = [];
+  final List<Set<Variable>> _writtenStack = [new Set<Variable>.identity()];
+
+  /// Stack of sets accumulating variables that are declared.
+  ///
+  /// A set is pushed onto the stack when a node is entered, and popped when
+  /// a node is left.
+  final List<Set<Variable>> _declaredStack = [new Set<Variable>.identity()];
 
   /// Stack of sets accumulating variables for which a potential write is
   /// captured by a local function or closure.
   ///
   /// A set is pushed onto the stack when a node is entered, and popped when
   /// a node is left.
-  final List<Set<Variable>> _capturedStack = [];
-
-  /// Stack of integers counting the number of entries in [_capturedStack] that
-  /// should be updated when a variable write is seen.
-  ///
-  /// When a closure is entered, the length of [_capturedStack] is pushed onto
-  /// this stack; when a node is left, it is popped.
-  ///
-  /// Each time a write occurs, we consult the top of this stack to determine
-  /// how many elements of [capturedStack] should be updated.
-  final List<int> _closureIndexStack = [];
+  final List<Set<Variable>> _capturedStack = [new Set<Variable>.identity()];
 
   AssignedVariables();
 
+  /// Queries the set of variables for which a potential write is captured by a
+  /// local function or closure anywhere in the code being analyzed.
+  Set<Variable> get capturedAnywhere => _capturedAnywhere;
+
+  /// Queries the set of variables that are potentially written to anywhere in
+  /// the code being analyzed.
+  Set<Variable> get writtenAnywhere => _writtenAnywhere;
+
   /// This method should be called during pre-traversal, to mark the start of a
   /// loop statement, switch statement, try statement, loop collection element,
   /// local function, or closure which might need to be queried later.
@@ -70,18 +82,26 @@
   /// covered, but the initializers should not.  Similarly, in a switch
   /// statement, the body of the switch statement should be covered, but the
   /// switch expression should not.
-  void beginNode({bool isClosure: false}) {
+  void beginNode() {
     _writtenStack.add(new Set<Variable>.identity());
-    if (isClosure) {
-      _closureIndexStack.add(_capturedStack.length);
-    }
+    _declaredStack.add(new Set<Variable>.identity());
     _capturedStack.add(new Set<Variable>.identity());
   }
 
   /// Queries the set of variables for which a potential write is captured by a
   /// local function or closure inside the [node].
   Set<Variable> capturedInNode(Node node) {
-    return _capturedInNode[node] ?? const {};
+    return _capturedInNode[node] ??
+        (throw new StateError('No information for $node'));
+  }
+
+  /// This method should be called during pre-traversal, to indicate that the
+  /// declaration of a variable has been found.
+  ///
+  /// It is not required for the declaration to be seen prior to its use (this
+  /// is to allow for error recovery in the analyzer).
+  void declare(Variable variable) {
+    _declaredStack.last.add(variable);
   }
 
   /// This method should be called during pre-traversal, to mark the end of a
@@ -92,185 +112,119 @@
   ///
   /// See [beginNode] for more details.
   void endNode(Node node, {bool isClosure: false}) {
-    _writtenInNode[node] = _writtenStack.removeLast();
-    _capturedInNode[node] = _capturedStack.removeLast();
+    Set<Variable> declaredInThisNode = _declaredStack.removeLast();
+    Set<Variable> writtenInThisNode = _writtenStack.removeLast()
+      ..removeAll(declaredInThisNode);
+    Set<Variable> capturedInThisNode = _capturedStack.removeLast()
+      ..removeAll(declaredInThisNode);
+    _writtenInNode[node] = writtenInThisNode;
+    _capturedInNode[node] = capturedInThisNode;
+    _writtenStack.last.addAll(writtenInThisNode);
+    _capturedStack.last.addAll(capturedInThisNode);
     if (isClosure) {
-      _closureIndexStack.removeLast();
+      _capturedStack.last.addAll(writtenInThisNode);
+      _capturedAnywhere.addAll(writtenInThisNode);
     }
   }
 
+  /// Call this after visiting the code to be analyzed, to check invariants.
+  void finish() {
+    assert(() {
+      assert(_writtenStack.length == 1);
+      assert(_declaredStack.length == 1);
+      assert(_capturedStack.length == 1);
+      Set<Variable> writtenInThisNode = _writtenStack.last;
+      Set<Variable> declaredInThisNode = _declaredStack.last;
+      Set<Variable> capturedInThisNode = _capturedStack.last;
+      Set<Variable> undeclaredWrites =
+          writtenInThisNode.difference(declaredInThisNode);
+      assert(undeclaredWrites.isEmpty,
+          'Variables written to but not declared: $undeclaredWrites');
+      Set<Variable> undeclaredCaptures =
+          capturedInThisNode.difference(declaredInThisNode);
+      assert(undeclaredCaptures.isEmpty,
+          'Variables captured but not declared: $undeclaredCaptures');
+      return true;
+    }());
+  }
+
   /// This method should be called during pre-traversal, to mark a write to a
   /// variable.
   void write(Variable variable) {
-    for (int i = 0; i < _writtenStack.length; ++i) {
-      _writtenStack[i].add(variable);
-    }
-    if (_closureIndexStack.isNotEmpty) {
-      int closureIndex = _closureIndexStack.last;
-      for (int i = 0; i < closureIndex; ++i) {
-        _capturedStack[i].add(variable);
-      }
-    }
+    _writtenStack.last.add(variable);
+    _writtenAnywhere.add(variable);
   }
 
   /// Queries the set of variables that are potentially written to inside the
   /// [node].
   Set<Variable> writtenInNode(Node node) {
-    return _writtenInNode[node] ?? const {};
+    return _writtenInNode[node] ??
+        (throw new StateError('No information for $node'));
   }
 }
 
-class FlowAnalysis<Statement, Expression, Variable, Type> {
-  /// The [NodeOperations], used to manipulate expressions.
-  final NodeOperations<Expression> nodeOperations;
-
-  /// The [TypeOperations], used to access types, and check subtyping.
-  final TypeOperations<Variable, Type> typeOperations;
-
-  /// The enclosing function body, used to check for potential mutations.
-  final FunctionBodyAccess<Variable> functionBody;
-
-  /// The stack of states of variables that are not definitely assigned.
-  final List<FlowModel<Variable, Type>> _stack = [];
-
-  /// The mapping from labeled [Statement]s to the index in the [_stack]
-  /// where the first related element is located.  The number of elements
-  /// is statement specific.  Loops have two elements: `break` and `continue`
-  /// states.
-  final Map<Statement, int> _statementToStackIndex = {};
-
-  FlowModel<Variable, Type> _current;
-
-  /// The last boolean condition, for [_conditionTrue] and [_conditionFalse].
-  Expression _condition;
-
-  /// The state when [_condition] evaluates to `true`.
-  FlowModel<Variable, Type> _conditionTrue;
-
-  /// The state when [_condition] evaluates to `false`.
-  FlowModel<Variable, Type> _conditionFalse;
-
+/// Implementation of flow analysis to be shared between the analyzer and the
+/// front end.
+///
+/// The client should create one instance of this class for every method, field,
+/// or top level variable to be analyzed, and call the appropriate methods
+/// while visiting the code for type inference.
+abstract class FlowAnalysis<Statement, Expression, Variable, Type> {
   factory FlowAnalysis(
-    NodeOperations<Expression> nodeOperations,
-    TypeOperations<Variable, Type> typeOperations,
-    FunctionBodyAccess<Variable> functionBody,
-  ) {
-    return new FlowAnalysis._(nodeOperations, typeOperations, functionBody);
-  }
-
-  FlowAnalysis._(this.nodeOperations, this.typeOperations, this.functionBody) {
-    _current = new FlowModel<Variable, Type>(true);
+      TypeOperations<Variable, Type> typeOperations,
+      Iterable<Variable> variablesWrittenAnywhere,
+      Iterable<Variable> variablesCapturedAnywhere) {
+    return new _FlowAnalysisImpl(typeOperations,
+        variablesWrittenAnywhere.toList(), variablesCapturedAnywhere.toList());
   }
 
   /// Return `true` if the current state is reachable.
-  bool get isReachable => _current.reachable;
+  bool get isReachable;
 
-  void booleanLiteral(Expression expression, bool value) {
-    _condition = expression;
-    if (value) {
-      _conditionTrue = _current;
-      _conditionFalse = _current.setReachable(false);
-    } else {
-      _conditionTrue = _current.setReachable(false);
-      _conditionFalse = _current;
-    }
-  }
+  /// Call this method when visiting a boolean literal expression.
+  void booleanLiteral(Expression expression, bool value);
 
-  void conditional_elseBegin(Expression thenExpression) {
-    FlowModel<Variable, Type> afterThen = _current;
-    FlowModel<Variable, Type> falseCondition = _stack.removeLast();
+  /// Call this method upon reaching the ":" part of a conditional expression
+  /// ("?:").  [thenExpression] should be the expression preceding the ":".
+  void conditional_elseBegin(Expression thenExpression);
 
-    _conditionalEnd(thenExpression);
-    // Tail of the stack: falseThen, trueThen
-
-    _stack.add(afterThen);
-    _current = falseCondition;
-  }
-
+  /// Call this method when finishing the visit of a conditional expression
+  /// ("?:").  [elseExpression] should be the expression preceding the ":", and
+  /// [conditionalExpression] should be the whole conditional expression.
   void conditional_end(
-      Expression conditionalExpression, Expression elseExpression) {
-    FlowModel<Variable, Type> afterThen = _stack.removeLast();
-    FlowModel<Variable, Type> afterElse = _current;
+      Expression conditionalExpression, Expression elseExpression);
 
-    _conditionalEnd(elseExpression);
-    // Tail of the stack: falseThen, trueThen, falseElse, trueElse
+  /// Call this method upon reaching the "?" part of a conditional expression
+  /// ("?:").  [condition] should be the expression preceding the "?".
+  void conditional_thenBegin(Expression condition);
 
-    FlowModel<Variable, Type> trueElse = _stack.removeLast();
-    FlowModel<Variable, Type> falseElse = _stack.removeLast();
+  /// Call this method before visiting the body of a "do-while" statement.
+  /// [loopAssigned] should be the set of variables that are assigned in the
+  /// body of the loop (or the condition), and [loopCaptured] should be the set
+  /// of variables that are captured by closures within the body of the loop (or
+  /// the condition).
+  void doStatement_bodyBegin(Statement doStatement,
+      Iterable<Variable> loopAssigned, Iterable<Variable> loopCaptured);
 
-    FlowModel<Variable, Type> trueThen = _stack.removeLast();
-    FlowModel<Variable, Type> falseThen = _stack.removeLast();
+  /// Call this method after visiting the body of a "do-while" statement, and
+  /// before visiting its condition.
+  void doStatement_conditionBegin();
 
-    FlowModel<Variable, Type> trueResult = _join(trueThen, trueElse);
-    FlowModel<Variable, Type> falseResult = _join(falseThen, falseElse);
+  /// Call this method after visiting the condition of a "do-while" statement.
+  /// [condition] should be the condition of the loop.
+  void doStatement_end(Expression condition);
 
-    _condition = conditionalExpression;
-    _conditionTrue = trueResult;
-    _conditionFalse = falseResult;
+  /// Call this method just after visiting a binary `==` or `!=` expression.
+  void equalityOp_end(Expression wholeExpression, Expression rightOperand,
+      {bool notEqual = false});
 
-    _current = _join(afterThen, afterElse);
-  }
-
-  void conditional_thenBegin(Expression condition) {
-    _conditionalEnd(condition);
-    // Tail of the stack: falseCondition, trueCondition
-
-    FlowModel<Variable, Type> trueCondition = _stack.removeLast();
-    _current = trueCondition;
-  }
-
-  /// The [binaryExpression] checks that the [variable] is, or is not, equal to
-  /// `null`.
-  void conditionEqNull(Expression binaryExpression, Variable variable,
-      {bool notEqual: false}) {
-    if (functionBody.isPotentiallyMutatedInClosure(variable)) {
-      return;
-    }
-
-    _condition = binaryExpression;
-    FlowModel<Variable, Type> currentModel =
-        _current.markNonNullable(typeOperations, variable);
-    if (notEqual) {
-      _conditionTrue = currentModel;
-      _conditionFalse = _current;
-    } else {
-      _conditionTrue = _current;
-      _conditionFalse = currentModel;
-    }
-  }
-
-  void doStatement_bodyBegin(
-      Statement doStatement, Iterable<Variable> loopAssigned) {
-    _current = _current.removePromotedAll(loopAssigned);
-
-    _statementToStackIndex[doStatement] = _stack.length;
-    _stack.add(null); // break
-    _stack.add(null); // continue
-  }
-
-  void doStatement_conditionBegin() {
-    // Tail of the stack: break, continue
-
-    FlowModel<Variable, Type> continueState = _stack.removeLast();
-    _current = _join(_current, continueState);
-  }
-
-  void doStatement_end(Expression condition) {
-    _conditionalEnd(condition);
-    // Tail of the stack:  break, falseCondition, trueCondition
-
-    _stack.removeLast(); // trueCondition
-    FlowModel<Variable, Type> falseCondition = _stack.removeLast();
-    FlowModel<Variable, Type> breakState = _stack.removeLast();
-
-    _current = _join(falseCondition, breakState);
-  }
+  /// Call this method just after visiting the left hand side of a binary `==`
+  /// or `!=` expression.
+  void equalityOp_rightBegin(Expression leftOperand);
 
   /// This method should be called at the conclusion of flow analysis for a top
   /// level function or method.  Performs assertion checks.
-  void finish() {
-    assert(_stack.isEmpty);
-  }
+  void finish();
 
   /// Call this method just before visiting the body of a conventional "for"
   /// statement or collection element.  See [for_conditionBegin] for details.
@@ -285,27 +239,7 @@
   /// the loop condition should cause any promotions to occur.  If [condition]
   /// is null, the condition is understood to be empty (equivalent to a
   /// condition of `true`).
-  void for_bodyBegin(Statement node, Expression condition) {
-    FlowModel<Variable, Type> trueCondition;
-    if (condition == null) {
-      trueCondition = _current;
-      _stack.add(_current.setReachable(false));
-    } else {
-      _conditionalEnd(condition);
-      // Tail of the stack: falseCondition, trueCondition
-
-      trueCondition = _stack.removeLast();
-    }
-    // Tail of the stack: falseCondition
-
-    if (node != null) {
-      _statementToStackIndex[node] = _stack.length;
-    }
-    _stack.add(null); // break
-    _stack.add(null); // continue
-
-    _current = trueCondition;
-  }
+  void for_bodyBegin(Statement node, Expression condition);
 
   /// Call this method just before visiting the condition of a conventional
   /// "for" statement or collection element.
@@ -327,29 +261,16 @@
   ///
   /// [loopAssigned] should be the set of variables that are assigned anywhere
   /// in the loop's condition, updaters, or body.
-  void for_conditionBegin(Set<Variable> loopAssigned) {
-    _current = _current.removePromotedAll(loopAssigned);
-  }
+  void for_conditionBegin(
+      Set<Variable> loopAssigned, Set<Variable> loopCaptured);
 
   /// Call this method just after visiting the updaters of a conventional "for"
   /// statement or collection element.  See [for_conditionBegin] for details.
-  void for_end() {
-    // Tail of the stack: falseCondition, break
-    FlowModel<Variable, Type> breakState = _stack.removeLast();
-    FlowModel<Variable, Type> falseCondition = _stack.removeLast();
-
-    _current = _join(falseCondition, breakState);
-  }
+  void for_end();
 
   /// Call this method just before visiting the updaters of a conventional "for"
   /// statement or collection element.  See [for_conditionBegin] for details.
-  void for_updaterBegin() {
-    // Tail of the stack: falseCondition, break, continue
-    FlowModel<Variable, Type> afterBody = _current;
-    FlowModel<Variable, Type> continueState = _stack.removeLast();
-
-    _current = _join(afterBody, continueState);
-  }
+  void for_updaterBegin();
 
   /// Call this method just before visiting the body of a "for-in" statement or
   /// collection element.
@@ -364,185 +285,120 @@
   /// [loopAssigned] should be the set of variables that are assigned anywhere
   /// in the loop's body.  [loopVariable] should be the loop variable, if it's a
   /// local variable, or `null` otherwise.
-  void forEach_bodyBegin(Set<Variable> loopAssigned, Variable loopVariable) {
-    _stack.add(_current);
-    _current = _current.removePromotedAll(loopAssigned);
-    if (loopVariable != null) {
-      assert(loopAssigned.contains(loopVariable));
-      _current = _current.write(loopVariable);
-    }
-  }
+  void forEach_bodyBegin(Iterable<Variable> loopAssigned,
+      Iterable<Variable> loopCaptured, Variable loopVariable);
 
   /// Call this method just before visiting the body of a "for-in" statement or
   /// collection element.  See [forEach_bodyBegin] for details.
-  void forEach_end() {
-    FlowModel<Variable, Type> afterIterable = _stack.removeLast();
-    _current = _join(_current, afterIterable);
-  }
+  void forEach_end();
 
-  void functionExpression_begin() {
-    _stack.add(_current);
+  /// Call this method just before visiting the body of a function expression or
+  /// local function.
+  void functionExpression_begin(Iterable<Variable> writeCaptured);
 
-    List<Variable> notPromoted = [];
-    for (MapEntry<Variable, VariableModel<Type>> entry
-        in _current.variableInfo.entries) {
-      Variable variable = entry.key;
-      Type promotedType = entry.value.promotedType;
-      if (promotedType != null &&
-          functionBody.isPotentiallyMutatedInScope(variable)) {
-        notPromoted.add(variable);
-      }
-    }
+  /// Call this method just after visiting the body of a function expression or
+  /// local function.
+  void functionExpression_end();
 
-    if (notPromoted.isNotEmpty) {
-      _current = _current.removePromotedAll(notPromoted);
-    }
-  }
+  /// Call this method when visiting a break statement.  [target] should be the
+  /// statement targeted by the break.
+  void handleBreak(Statement target);
 
-  void functionExpression_end() {
-    _current = _stack.removeLast();
-  }
-
-  void handleBreak(Statement target) {
-    int breakIndex = _statementToStackIndex[target];
-    if (breakIndex != null) {
-      _stack[breakIndex] = _join(_stack[breakIndex], _current);
-    }
-    _current = _current.setReachable(false);
-  }
-
-  void handleContinue(Statement target) {
-    int breakIndex = _statementToStackIndex[target];
-    if (breakIndex != null) {
-      int continueIndex = breakIndex + 1;
-      _stack[continueIndex] = _join(_stack[continueIndex], _current);
-    }
-    _current = _current.setReachable(false);
-  }
+  /// Call this method when visiting a continue statement.  [target] should be
+  /// the statement targeted by the continue.
+  void handleContinue(Statement target);
 
   /// Register the fact that the current state definitely exists, e.g. returns
   /// from the body, throws an exception, etc.
-  void handleExit() {
-    _current = _current.setReachable(false);
-  }
+  void handleExit();
 
-  void ifNullExpression_end() {
-    FlowModel<Variable, Type> afterLeft = _stack.removeLast();
-    _current = _join(_current, afterLeft);
-  }
+  /// Call this method after visiting the RHS of an if-null ("??") expression.
+  void ifNullExpression_end();
 
-  void ifNullExpression_rightBegin() {
-    _stack.add(_current); // afterLeft
-  }
+  /// Call this method after visiting the LHS of an if-null ("??") expression.
+  void ifNullExpression_rightBegin();
 
-  void ifStatement_elseBegin() {
-    FlowModel<Variable, Type> afterThen = _current;
-    FlowModel<Variable, Type> falseCondition = _stack.removeLast();
-    _stack.add(afterThen);
-    _current = falseCondition;
-  }
+  /// Call this method after visiting the "then" part of an if statement, and
+  /// before visiting the "else" part.
+  void ifStatement_elseBegin();
 
-  void ifStatement_end(bool hasElse) {
-    FlowModel<Variable, Type> afterThen;
-    FlowModel<Variable, Type> afterElse;
-    if (hasElse) {
-      afterThen = _stack.removeLast();
-      afterElse = _current;
-    } else {
-      afterThen = _current; // no `else`, so `then` is still current
-      afterElse = _stack.removeLast(); // `falseCond` is still on the stack
-    }
-    _current = _join(afterThen, afterElse);
-  }
+  /// Call this method after visiting an if statement.
+  void ifStatement_end(bool hasElse);
 
-  void ifStatement_thenBegin(Expression condition) {
-    _conditionalEnd(condition);
-    // Tail of the stack:  falseCondition, trueCondition
+  /// Call this method after visiting the condition part of an if statement.
+  /// [condition] should be the if statement's condition.
+  ///
+  /// The order of visiting an if statement with no "else" part should be:
+  /// - Visit the condition
+  /// - Call [ifStatement_thenBegin]
+  /// - Visit the "then" statement
+  /// - Call [ifStatement_end], passing `false` for `hasElse`.
+  ///
+  /// The order of visiting an if statement with an "else" part should be:
+  /// - Visit the condition
+  /// - Call [ifStatement_thenBegin]
+  /// - Visit the "then" statement
+  /// - Call [ifStatement_elseBegin]
+  /// - Visit the "else" statement
+  /// - Call [ifStatement_end], passing `true` for `hasElse`.
+  void ifStatement_thenBegin(Expression condition);
 
-    FlowModel<Variable, Type> trueCondition = _stack.removeLast();
-    _current = trueCondition;
-  }
+  /// Register an initialized declaration of the given [variable] in the current
+  /// state.  Should also be called for function parameters.
+  void initialize(Variable variable);
 
   /// Return whether the [variable] is definitely assigned in the current state.
-  bool isAssigned(Variable variable) {
-    return _current.infoFor(variable).assigned;
-  }
+  bool isAssigned(Variable variable);
 
+  /// Call this method after visiting the LHS of an "is" expression that checks
+  /// the type of a promotable variable.
+  /// [isExpression] should be the complete expression.  [variable] should be
+  /// the promotable variable.  [isNot] should be a boolean indicating whether
+  /// this is an "is" or an "is!" expression.  [type] should be the type being
+  /// checked.
   void isExpression_end(
-      Expression isExpression, Variable variable, bool isNot, Type type) {
-    if (functionBody.isPotentiallyMutatedInClosure(variable)) {
-      return;
-    }
+      Expression isExpression, Variable variable, bool isNot, Type type);
 
-    _condition = isExpression;
-    if (isNot) {
-      _conditionTrue = _current;
-      _conditionFalse = _current.promote(typeOperations, variable, type);
-    } else {
-      _conditionTrue = _current.promote(typeOperations, variable, type);
-      _conditionFalse = _current;
-    }
-  }
-
+  /// Call this method after visiting the RHS of a logical binary operation
+  /// ("||" or "&&").
+  /// [wholeExpression] should be the whole logical binary expression.
+  /// [rightOperand] should be the RHS.  [isAnd] should indicate whether the
+  /// logical operator is "&&" or "||".
   void logicalBinaryOp_end(Expression wholeExpression, Expression rightOperand,
-      {@required bool isAnd}) {
-    _conditionalEnd(rightOperand);
-    // Tail of the stack: falseLeft, trueLeft, falseRight, trueRight
+      {@required bool isAnd});
 
-    FlowModel<Variable, Type> trueRight = _stack.removeLast();
-    FlowModel<Variable, Type> falseRight = _stack.removeLast();
-
-    FlowModel<Variable, Type> trueLeft = _stack.removeLast();
-    FlowModel<Variable, Type> falseLeft = _stack.removeLast();
-
-    FlowModel<Variable, Type> trueResult;
-    FlowModel<Variable, Type> falseResult;
-    if (isAnd) {
-      trueResult = trueRight;
-      falseResult = _join(falseLeft, falseRight);
-    } else {
-      trueResult = _join(trueLeft, trueRight);
-      falseResult = falseRight;
-    }
-
-    FlowModel<Variable, Type> afterResult = _join(trueResult, falseResult);
-
-    _condition = wholeExpression;
-    _conditionTrue = trueResult;
-    _conditionFalse = falseResult;
-
-    _current = afterResult;
-  }
-
+  /// Call this method after visiting the LHS of a logical binary operation
+  /// ("||" or "&&").
+  /// [rightOperand] should be the LHS.  [isAnd] should indicate whether the
+  /// logical operator is "&&" or "||".
   void logicalBinaryOp_rightBegin(Expression leftOperand,
-      {@required bool isAnd}) {
-    _conditionalEnd(leftOperand);
-    // Tail of the stack: falseLeft, trueLeft
+      {@required bool isAnd});
 
-    if (isAnd) {
-      FlowModel<Variable, Type> trueLeft = _stack.last;
-      _current = trueLeft;
-    } else {
-      FlowModel<Variable, Type> falseLeft = _stack[_stack.length - 2];
-      _current = falseLeft;
-    }
-  }
+  /// Call this method after visiting a logical not ("!") expression.
+  /// [notExpression] should be the complete expression.  [operand] should be
+  /// the subexpression whose logical value is being negated.
+  void logicalNot_end(Expression notExpression, Expression operand);
 
-  void logicalNot_end(Expression notExpression, Expression operand) {
-    _conditionalEnd(operand);
-    FlowModel<Variable, Type> trueExpr = _stack.removeLast();
-    FlowModel<Variable, Type> falseExpr = _stack.removeLast();
+  /// Call this method just after visiting a non-null assertion (`x!`)
+  /// expression.
+  void nonNullAssert_end(Expression operand);
 
-    _condition = notExpression;
-    _conditionTrue = falseExpr;
-    _conditionFalse = trueExpr;
-  }
+  /// Call this method when encountering an expression that is a `null` literal.
+  void nullLiteral(Expression expression);
+
+  /// Call this method just after visiting a parenthesized expression.
+  ///
+  /// This is only necessary if the implementation uses a different [Expression]
+  /// object to represent a parenthesized expression and its contents.
+  void parenthesizedExpression(
+      Expression outerExpression, Expression innerExpression);
 
   /// Retrieves the type that the [variable] is promoted to, if the [variable]
   /// is currently promoted.  Otherwise returns `null`.
-  Type promotedType(Variable variable) {
-    return _current.infoFor(variable).promotedType;
-  }
+  ///
+  /// For testing only.  Please use [variableRead] instead.
+  @visibleForTesting
+  Type promotedType(Variable variable);
 
   /// Call this method just before visiting one of the cases in the body of a
   /// switch statement.  See [switchStatement_expressionEnd] for details.
@@ -551,34 +407,14 @@
   ///
   /// The [notPromoted] set contains all variables that are potentially assigned
   /// within the body of the switch statement.
-  void switchStatement_beginCase(
-      bool hasLabel, Iterable<Variable> notPromoted) {
-    if (hasLabel) {
-      _current = _stack.last.removePromotedAll(notPromoted);
-    } else {
-      _current = _stack.last;
-    }
-  }
+  void switchStatement_beginCase(bool hasLabel, Iterable<Variable> notPromoted,
+      Iterable<Variable> captured);
 
   /// Call this method just after visiting the body of a switch statement.  See
   /// [switchStatement_expressionEnd] for details.
   ///
   /// [hasDefault] indicates whether the switch statement had a "default" case.
-  void switchStatement_end(bool hasDefault) {
-    // Tail of the stack: break, continue, afterExpression
-    FlowModel<Variable, Type> afterExpression = _stack.removeLast();
-    _stack.removeLast(); // continue
-    FlowModel<Variable, Type> breakState = _stack.removeLast();
-
-    // It is allowed to "fall off" the end of a switch statement, so join the
-    // current state to any breaks that were found previously.
-    breakState = _join(breakState, _current);
-
-    // And, if there is an implicit fall-through default, join it to any breaks.
-    if (!hasDefault) breakState = _join(breakState, afterExpression);
-
-    _current = breakState;
-  }
+  void switchStatement_end(bool hasDefault);
 
   /// Call this method just after visiting the expression part of a switch
   /// statement.
@@ -590,104 +426,109 @@
   ///   - Call [switchStatement_beginCase].
   ///   - Visit the case.
   /// - Call [switchStatement_end].
-  void switchStatement_expressionEnd(Statement switchStatement) {
-    _statementToStackIndex[switchStatement] = _stack.length;
-    _stack.add(null); // break
-    _stack.add(null); // continue
-    _stack.add(_current); // afterExpression
-  }
+  void switchStatement_expressionEnd(Statement switchStatement);
 
-  void tryCatchStatement_bodyBegin() {
-    _stack.add(_current);
-    // Tail of the stack: beforeBody
-  }
+  /// Call this method just before visiting the body of a "try/catch" statement.
+  ///
+  /// The order of visiting a "try/catch" statement should be:
+  /// - Call [tryCatchStatement_bodyBegin]
+  /// - Visit the try block
+  /// - Call [tryCatchStatement_bodyEnd]
+  /// - For each catch block:
+  ///   - Call [tryCatchStatement_catchBegin]
+  ///   - Call [initialize] for the exception and stack trace variables
+  ///   - Visit the catch block
+  ///   - Call [tryCatchStatement_catchEnd]
+  /// - Call [tryCatchStatement_end]
+  ///
+  /// The order of visiting a "try/catch/finally" statement should be:
+  /// - Call [tryFinallyStatement_bodyBegin]
+  /// - Call [tryCatchStatement_bodyBegin]
+  /// - Visit the try block
+  /// - Call [tryCatchStatement_bodyEnd]
+  /// - For each catch block:
+  ///   - Call [tryCatchStatement_catchBegin]
+  ///   - Call [initialize] for the exception and stack trace variables
+  ///   - Visit the catch block
+  ///   - Call [tryCatchStatement_catchEnd]
+  /// - Call [tryCatchStatement_end]
+  /// - Call [tryFinallyStatement_finallyBegin]
+  /// - Visit the finally block
+  /// - Call [tryFinallyStatement_end]
+  void tryCatchStatement_bodyBegin();
 
-  void tryCatchStatement_bodyEnd(Iterable<Variable> assignedInBody) {
-    FlowModel<Variable, Type> beforeBody = _stack.removeLast();
-    FlowModel<Variable, Type> beforeCatch =
-        beforeBody.removePromotedAll(assignedInBody);
-    _stack.add(beforeCatch);
-    _stack.add(_current); // afterBodyAndCatches
-    // Tail of the stack: beforeCatch, afterBodyAndCatches
-  }
+  /// Call this method just after visiting the body of a "try/catch" statement.
+  /// See [tryCatchStatement_bodyBegin] for details.
+  ///
+  /// [assignedInBody] should be the set of variables assigned in the "try" part
+  /// of the statement.  [capturedInBody] should be the set of variables
+  /// captured by closures in the "try" part of the statement.
+  void tryCatchStatement_bodyEnd(
+      Iterable<Variable> assignedInBody, Iterable<Variable> capturedInBody);
 
-  void tryCatchStatement_catchBegin() {
-    FlowModel<Variable, Type> beforeCatch = _stack[_stack.length - 2];
-    _current = beforeCatch;
-  }
+  /// Call this method just before visiting a catch clause of a "try/catch"
+  /// statement.  See [tryCatchStatement_bodyBegin] for details.
+  void tryCatchStatement_catchBegin();
 
-  void tryCatchStatement_catchEnd() {
-    FlowModel<Variable, Type> afterBodyAndCatches = _stack.last;
-    _stack.last = _join(afterBodyAndCatches, _current);
-  }
+  /// Call this method just after visiting a catch clause of a "try/catch"
+  /// statement.  See [tryCatchStatement_bodyBegin] for details.
+  void tryCatchStatement_catchEnd();
 
-  void tryCatchStatement_end() {
-    FlowModel<Variable, Type> afterBodyAndCatches = _stack.removeLast();
-    _stack.removeLast(); // beforeCatch
-    _current = afterBodyAndCatches;
-  }
+  /// Call this method just after visiting a "try/catch" statement.  See
+  /// [tryCatchStatement_bodyBegin] for details.
+  void tryCatchStatement_end();
 
-  void tryFinallyStatement_bodyBegin() {
-    _stack.add(_current); // beforeTry
-  }
+  /// Call this method just before visiting the body of a "try/finally"
+  /// statement.
+  ///
+  /// The order of visiting a "try/finally" statement should be:
+  /// - Call [tryFinallyStatement_bodyBegin]
+  /// - Visit the try block
+  /// - Call [tryFinallyStatement_finallyBegin]
+  /// - Visit the finally block
+  /// - Call [tryFinallyStatement_end]
+  ///
+  /// See [tryCatchStatement_bodyBegin] for the order of visiting a
+  /// "try/catch/finally" statement.
+  void tryFinallyStatement_bodyBegin();
 
-  void tryFinallyStatement_end(Set<Variable> assignedInFinally) {
-    FlowModel<Variable, Type> afterBody = _stack.removeLast();
-    _current = _current.restrict(typeOperations, afterBody, assignedInFinally);
-  }
+  /// Call this method just after visiting a "try/finally" statement.
+  /// See [tryFinallyStatement_bodyBegin] for details.
+  ///
+  /// [assignedInFinally] should be the set of variables assigned in the
+  /// "finally" part of the statement.
+  void tryFinallyStatement_end(Set<Variable> assignedInFinally);
 
-  void tryFinallyStatement_finallyBegin(Iterable<Variable> assignedInBody) {
-    FlowModel<Variable, Type> beforeTry = _stack.removeLast();
-    FlowModel<Variable, Type> afterBody = _current;
-    _stack.add(afterBody);
-    _current = _join(afterBody, beforeTry.removePromotedAll(assignedInBody));
-  }
+  /// Call this method just before visiting the finally block of a "try/finally"
+  /// statement.  See [tryFinallyStatement_bodyBegin] for details.
+  void tryFinallyStatement_finallyBegin(
+      Iterable<Variable> assignedInBody, Iterable<Variable> capturedInBody);
 
-  void whileStatement_bodyBegin(
-      Statement whileStatement, Expression condition) {
-    _conditionalEnd(condition);
-    // Tail of the stack: falseCondition, trueCondition
+  /// Call this method when encountering an expression that reads the value of
+  /// a variable.
+  ///
+  /// If the variable's type is currently promoted, the promoted type is
+  /// returned.  Otherwise `null` is returned.
+  Type variableRead(Expression expression, Variable variable);
 
-    FlowModel<Variable, Type> trueCondition = _stack.removeLast();
+  /// Call this method after visiting the condition part of a "while" statement.
+  /// [whileStatement] should be the full while statement.  [condition] should
+  /// be the condition part of the while statement.
+  void whileStatement_bodyBegin(Statement whileStatement, Expression condition);
 
-    _statementToStackIndex[whileStatement] = _stack.length;
-    _stack.add(null); // break
-    _stack.add(null); // continue
+  /// Call this method before visiting the condition part of a "while"
+  /// statement.
+  /// [loopAssigned] should be the set of variables assigned in the body of the
+  /// loop (or in the condition).  [loopCaptured] should be the set of variables
+  /// captured by closures in the body of the loop (or in the condition).
+  void whileStatement_conditionBegin(
+      Iterable<Variable> loopAssigned, Iterable<Variable> loopCaptured);
 
-    _current = trueCondition;
-  }
-
-  void whileStatement_conditionBegin(Iterable<Variable> loopAssigned) {
-    _current = _current.removePromotedAll(loopAssigned);
-  }
-
-  void whileStatement_end() {
-    _stack.removeLast(); // continue
-    FlowModel<Variable, Type> breakState = _stack.removeLast();
-    FlowModel<Variable, Type> falseCondition = _stack.removeLast();
-
-    _current = _join(falseCondition, breakState);
-  }
+  /// Call this method after visiting a "while" statement.
+  void whileStatement_end();
 
   /// Register write of the given [variable] in the current state.
-  void write(Variable variable) {
-    _current = _current.write(variable);
-  }
-
-  void _conditionalEnd(Expression condition) {
-    condition = nodeOperations.unwrapParenthesized(condition);
-    if (identical(condition, _condition)) {
-      _stack.add(_conditionFalse);
-      _stack.add(_conditionTrue);
-    } else {
-      _stack.add(_current);
-      _stack.add(_current);
-    }
-  }
-
-  FlowModel<Variable, Type> _join(
-          FlowModel<Variable, Type> first, FlowModel<Variable, Type> second) =>
-      FlowModel.join(typeOperations, first, second);
+  void write(Variable variable);
 }
 
 /// An instance of the [FlowModel] class represents the information gathered by
@@ -748,6 +589,7 @@
   FlowModel<Variable, Type> markNonNullable(
       TypeOperations<Variable, Type> typeOperations, Variable variable) {
     VariableModel<Type> info = infoFor(variable);
+    if (info.writeCaptured) return this;
     Type previousType = info.promotedType;
     previousType ??= typeOperations.variableType(variable);
     Type type = typeOperations.promoteToNonNull(previousType);
@@ -770,6 +612,7 @@
     Type type,
   ) {
     VariableModel<Type> info = infoFor(variable);
+    if (info.writeCaptured) return this;
     Type previousType = info.promotedType;
     previousType ??= typeOperations.variableType(variable);
 
@@ -780,8 +623,8 @@
     return _updateVariableInfo(variable, info.withPromotedType(type));
   }
 
-  /// Updates the state to indicate that the given [variables] are no longer
-  /// promoted; they are presumed to have their declared types.
+  /// Updates the state to indicate that the given [writtenVariables] are no
+  /// longer promoted; they are presumed to have their declared types.
   ///
   /// This is used at the top of loops to conservatively cancel the promotion of
   /// variables that are modified within the loop, so that we correctly analyze
@@ -799,15 +642,28 @@
   /// and only remove promotions if it can be shown that they aren't restored
   /// later in the loop body.  If we switch to a fixed point analysis, we should
   /// be able to remove this method.
-  FlowModel<Variable, Type> removePromotedAll(Iterable<Variable> variables) {
+  FlowModel<Variable, Type> removePromotedAll(
+      Iterable<Variable> writtenVariables,
+      Iterable<Variable> capturedVariables) {
     Map<Variable, VariableModel<Type>> newVariableInfo;
-    for (Variable variable in variables) {
+    for (Variable variable in writtenVariables) {
       VariableModel<Type> info = infoFor(variable);
       if (info.promotedType != null) {
         (newVariableInfo ??= new Map<Variable, VariableModel<Type>>.from(
             variableInfo))[variable] = info.withPromotedType(null);
       }
     }
+    for (Variable variable in capturedVariables) {
+      VariableModel<Type> info = variableInfo[variable];
+      if (info == null) {
+        (newVariableInfo ??= new Map<Variable, VariableModel<Type>>.from(
+                variableInfo))[variable] =
+            new VariableModel<Type>(null, false, true);
+      } else if (!info.writeCaptured) {
+        (newVariableInfo ??= new Map<Variable, VariableModel<Type>>.from(
+            variableInfo))[variable] = info.writeCapture();
+      }
+    }
     if (newVariableInfo == null) return this;
     return new FlowModel<Variable, Type>._(reachable, newVariableInfo);
   }
@@ -1017,19 +873,6 @@
   }
 }
 
-/// Accessor for function body information.
-abstract class FunctionBodyAccess<Variable> {
-  bool isPotentiallyMutatedInClosure(Variable variable);
-
-  bool isPotentiallyMutatedInScope(Variable variable);
-}
-
-/// Operations on nodes, abstracted from concrete node interfaces.
-abstract class NodeOperations<Expression> {
-  /// If the [node] is a parenthesized expression, recursively unwrap it.
-  Expression unwrapParenthesized(Expression node);
-}
-
 /// Operations on types, abstracted from concrete type interfaces.
 abstract class TypeOperations<Variable, Type> {
   /// Returns `true` if [type1] and [type2] are the same type.
@@ -1063,19 +906,27 @@
   /// Indicates whether the variable has definitely been assigned.
   final bool assigned;
 
-  VariableModel(this.promotedType, this.assigned);
+  /// Indicates whether the variable has been write captured.
+  final bool writeCaptured;
+
+  VariableModel(this.promotedType, this.assigned, this.writeCaptured) {
+    assert(!writeCaptured || promotedType == null,
+        "Write-captured variables can't be promoted");
+  }
 
   /// Creates a [VariableModel] representing a variable that's never been seen
   /// before.
   VariableModel.fresh()
       : promotedType = null,
-        assigned = false;
+        assigned = false,
+        writeCaptured = false;
 
   @override
   bool operator ==(Object other) {
     return other is VariableModel<Type> &&
         this.promotedType == other.promotedType &&
-        this.assigned == other.assigned;
+        this.assigned == other.assigned &&
+        this.writeCaptured == other.writeCaptured;
   }
 
   /// Returns an updated model reflect a control path that is known to have
@@ -1084,31 +935,41 @@
   VariableModel<Type> restrict(TypeOperations<Object, Type> typeOperations,
       VariableModel<Type> otherModel, bool unsafe) {
     Type thisType = promotedType;
-    Type otherType = otherModel?.promotedType;
+    Type otherType = otherModel.promotedType;
     bool newAssigned = assigned || otherModel.assigned;
+    bool newWriteCaptured = writeCaptured || otherModel.writeCaptured;
     if (!unsafe) {
       if (otherType != null &&
           (thisType == null ||
               typeOperations.isSubtypeOf(otherType, thisType))) {
-        return _identicalOrNew(this, otherModel, otherType, newAssigned);
+        return _identicalOrNew(
+            this, otherModel, otherType, newAssigned, newWriteCaptured);
       }
     }
-    return _identicalOrNew(this, otherModel, thisType, newAssigned);
+    return _identicalOrNew(
+        this, otherModel, thisType, newAssigned, newWriteCaptured);
   }
 
   @override
-  String toString() => 'VariableModel($promotedType, $assigned)';
+  String toString() =>
+      'VariableModel($promotedType, $assigned, $writeCaptured)';
 
   /// Returns a new [VariableModel] where the promoted type is replaced with
   /// [promotedType].
   VariableModel<Type> withPromotedType(Type promotedType) =>
-      new VariableModel<Type>(promotedType, assigned);
+      new VariableModel<Type>(promotedType, assigned, writeCaptured);
 
   /// Returns a new [VariableModel] reflecting the fact that the variable was
   /// just written to.
   VariableModel<Type> write() {
     if (promotedType == null && assigned) return this;
-    return new VariableModel<Type>(null, true);
+    return new VariableModel<Type>(null, true, writeCaptured);
+  }
+
+  /// Returns a new [VariableModel] reflecting the fact that the variable has
+  /// been write-captured.
+  VariableModel<Type> writeCapture() {
+    return new VariableModel<Type>(null, assigned, true);
   }
 
   /// Joins two variable models.  See [FlowModel.join] for details.
@@ -1131,21 +992,724 @@
       newPromotedType = null;
     }
     bool newAssigned = first.assigned && second.assigned;
-    return _identicalOrNew(first, second, newPromotedType, newAssigned);
+    bool newWriteCaptured = first.writeCaptured || second.writeCaptured;
+    return _identicalOrNew(
+        first, second, newPromotedType, newAssigned, newWriteCaptured);
   }
 
   /// Creates a new [VariableModel] object, unless it is equivalent to either
   /// [first] or [second], in which case one of those objects is re-used.
-  static VariableModel<Type> _identicalOrNew<Type>(VariableModel<Type> first,
-      VariableModel<Type> second, Type newPromotedType, bool newAssigned) {
+  static VariableModel<Type> _identicalOrNew<Type>(
+      VariableModel<Type> first,
+      VariableModel<Type> second,
+      Type newPromotedType,
+      bool newAssigned,
+      bool newWriteCaptured) {
     if (identical(first.promotedType, newPromotedType) &&
-        first.assigned == newAssigned) {
+        first.assigned == newAssigned &&
+        first.writeCaptured == newWriteCaptured) {
       return first;
     } else if (identical(second.promotedType, newPromotedType) &&
-        second.assigned == newAssigned) {
+        second.assigned == newAssigned &&
+        second.writeCaptured == newWriteCaptured) {
       return second;
     } else {
-      return new VariableModel<Type>(newPromotedType, newAssigned);
+      return new VariableModel<Type>(
+          newPromotedType, newAssigned, newWriteCaptured);
     }
   }
 }
+
+/// [_FlowContext] representing a language construct that branches on a boolean
+/// condition, such as an `if` statement, conditional expression, or a logical
+/// binary operator.
+class _BranchContext<Variable, Type> extends _FlowContext {
+  /// Flow models associated with the condition being branched on.
+  final _ExpressionInfo<Variable, Type> _conditionInfo;
+
+  _BranchContext(this._conditionInfo);
+}
+
+/// [_FlowContext] representing a language construct that can be targeted by
+/// `break` or `continue` statements, such as a loop or switch statement.
+class _BranchTargetContext<Variable, Type> extends _FlowContext {
+  /// Accumulated flow model for all `break` statements seen so far, or `null`
+  /// if no `break` statements have been seen yet.
+  FlowModel<Variable, Type> _breakModel;
+
+  /// Accumulated flow model for all `continue` statements seen so far, or
+  /// `null` if no `continue` statements have been seen yet.
+  FlowModel<Variable, Type> _continueModel;
+}
+
+/// [_FlowContext] representing a conditional expression.
+class _ConditionalContext<Variable, Type>
+    extends _BranchContext<Variable, Type> {
+  /// Flow models associated with the value of the conditional expression in the
+  /// circumstance where the "then" branch is taken.
+  _ExpressionInfo<Variable, Type> _thenInfo;
+
+  _ConditionalContext(_ExpressionInfo<Variable, Type> conditionInfo)
+      : super(conditionInfo);
+}
+
+/// A collection of flow models representing the possible outcomes of evaluating
+/// an expression that are relevant to flow analysis.
+class _ExpressionInfo<Variable, Type> {
+  /// The state after the expression evaluates, if we don't care what it
+  /// evaluates to.
+  final FlowModel<Variable, Type> _after;
+
+  /// The state after the expression evaluates, if it evaluates to `true`.
+  final FlowModel<Variable, Type> _ifTrue;
+
+  /// The state after the expression evaluates, if it evaluates to `false`.
+  final FlowModel<Variable, Type> _ifFalse;
+
+  _ExpressionInfo(this._after, this._ifTrue, this._ifFalse);
+}
+
+class _FlowAnalysisImpl<Statement, Expression, Variable, Type>
+    implements FlowAnalysis<Statement, Expression, Variable, Type> {
+  final List<Variable> _variablesWrittenAnywhere;
+
+  final List<Variable> _variablesCapturedAnywhere;
+
+  /// The [TypeOperations], used to access types, and check subtyping.
+  final TypeOperations<Variable, Type> typeOperations;
+
+  /// Stack of [_FlowContext] objects representing the statements and
+  /// expressions that are currently being visited.
+  final List<_FlowContext> _stack = [];
+
+  /// The mapping from [Statement]s that can act as targets for `break` and
+  /// `continue` statements (i.e. loops and switch statements) to the to their
+  /// context information.
+  final Map<Statement, _BranchTargetContext<Variable, Type>>
+      _statementToContext = {};
+
+  FlowModel<Variable, Type> _current;
+
+  /// The most recently visited expression for which an [_ExpressionInfo] object
+  /// exists, or `null` if no expression has been visited that has a
+  /// corresponding [_ExpressionInfo] object.
+  Expression _expressionWithInfo;
+
+  /// If [_expressionWithInfo] is not `null`, the [_ExpressionInfo] object
+  /// corresponding to it.  Otherwise `null`.
+  _ExpressionInfo<Variable, Type> _expressionInfo;
+
+  int _functionNestingLevel = 0;
+
+  _FlowAnalysisImpl(this.typeOperations, this._variablesWrittenAnywhere,
+      this._variablesCapturedAnywhere) {
+    _current = new FlowModel<Variable, Type>(true);
+  }
+
+  @override
+  bool get isReachable => _current.reachable;
+
+  @override
+  void booleanLiteral(Expression expression, bool value) {
+    FlowModel<Variable, Type> unreachable = _current.setReachable(false);
+    _storeExpressionInfo(
+        expression,
+        value
+            ? new _ExpressionInfo(_current, _current, unreachable)
+            : new _ExpressionInfo(_current, unreachable, _current));
+  }
+
+  @override
+  void conditional_elseBegin(Expression thenExpression) {
+    _ConditionalContext<Variable, Type> context =
+        _stack.last as _ConditionalContext<Variable, Type>;
+    context._thenInfo = _expressionEnd(thenExpression);
+    _current = context._conditionInfo._ifFalse;
+  }
+
+  @override
+  void conditional_end(
+      Expression conditionalExpression, Expression elseExpression) {
+    _ConditionalContext<Variable, Type> context =
+        _stack.removeLast() as _ConditionalContext<Variable, Type>;
+    _ExpressionInfo<Variable, Type> thenInfo = context._thenInfo;
+    _ExpressionInfo<Variable, Type> elseInfo = _expressionEnd(elseExpression);
+    _storeExpressionInfo(
+        conditionalExpression,
+        new _ExpressionInfo(
+            _join(thenInfo._after, elseInfo._after),
+            _join(thenInfo._ifTrue, elseInfo._ifTrue),
+            _join(thenInfo._ifFalse, elseInfo._ifFalse)));
+  }
+
+  @override
+  void conditional_thenBegin(Expression condition) {
+    _ExpressionInfo<Variable, Type> conditionInfo = _expressionEnd(condition);
+    _stack.add(new _ConditionalContext(conditionInfo));
+    _current = conditionInfo._ifTrue;
+  }
+
+  @override
+  void doStatement_bodyBegin(Statement doStatement,
+      Iterable<Variable> loopAssigned, Iterable<Variable> loopCaptured) {
+    _BranchTargetContext<Variable, Type> context =
+        new _BranchTargetContext<Variable, Type>();
+    _stack.add(context);
+    _current = _current.removePromotedAll(loopAssigned, loopCaptured);
+    _statementToContext[doStatement] = context;
+  }
+
+  @override
+  void doStatement_conditionBegin() {
+    _BranchTargetContext<Variable, Type> context =
+        _stack.last as _BranchTargetContext<Variable, Type>;
+    _current = _join(_current, context._continueModel);
+  }
+
+  @override
+  void doStatement_end(Expression condition) {
+    _BranchTargetContext<Variable, Type> context =
+        _stack.removeLast() as _BranchTargetContext<Variable, Type>;
+    _current = _join(_expressionEnd(condition)._ifFalse, context._breakModel);
+  }
+
+  @override
+  void equalityOp_end(Expression wholeExpression, Expression rightOperand,
+      {bool notEqual = false}) {
+    _BranchContext<Variable, Type> context =
+        _stack.removeLast() as _BranchContext<Variable, Type>;
+    _ExpressionInfo<Variable, Type> lhsInfo = context._conditionInfo;
+    _ExpressionInfo<Variable, Type> rhsInfo = _getExpressionInfo(rightOperand);
+    Variable variable;
+    if (lhsInfo is _NullInfo<Variable, Type> &&
+        rhsInfo is _VariableReadInfo<Variable, Type>) {
+      variable = rhsInfo._variable;
+    } else if (rhsInfo is _NullInfo<Variable, Type> &&
+        lhsInfo is _VariableReadInfo<Variable, Type>) {
+      variable = lhsInfo._variable;
+    } else {
+      return;
+    }
+    FlowModel<Variable, Type> ifNotNull =
+        _current.markNonNullable(typeOperations, variable);
+    _storeExpressionInfo(
+        wholeExpression,
+        notEqual
+            ? new _ExpressionInfo(_current, ifNotNull, _current)
+            : new _ExpressionInfo(_current, _current, ifNotNull));
+  }
+
+  @override
+  void equalityOp_rightBegin(Expression leftOperand) {
+    _stack.add(
+        new _BranchContext<Variable, Type>(_getExpressionInfo(leftOperand)));
+  }
+
+  @override
+  void finish() {
+    assert(_stack.isEmpty);
+  }
+
+  @override
+  void for_bodyBegin(Statement node, Expression condition) {
+    _ExpressionInfo<Variable, Type> conditionInfo = condition == null
+        ? new _ExpressionInfo(_current, _current, _current.setReachable(false))
+        : _expressionEnd(condition);
+    _WhileContext<Variable, Type> context =
+        new _WhileContext<Variable, Type>(conditionInfo);
+    _stack.add(context);
+    if (node != null) {
+      _statementToContext[node] = context;
+    }
+    _current = conditionInfo._ifTrue;
+  }
+
+  @override
+  void for_conditionBegin(
+      Set<Variable> loopAssigned, Set<Variable> loopCaptured) {
+    _current = _current.removePromotedAll(loopAssigned, loopCaptured);
+  }
+
+  @override
+  void for_end() {
+    _WhileContext<Variable, Type> context =
+        _stack.removeLast() as _WhileContext<Variable, Type>;
+    // Tail of the stack: falseCondition, break
+    FlowModel<Variable, Type> breakState = context._breakModel;
+    FlowModel<Variable, Type> falseCondition = context._conditionInfo._ifFalse;
+
+    _current = _join(falseCondition, breakState);
+  }
+
+  @override
+  void for_updaterBegin() {
+    _WhileContext<Variable, Type> context =
+        _stack.last as _WhileContext<Variable, Type>;
+    _current = _join(_current, context._continueModel);
+  }
+
+  @override
+  void forEach_bodyBegin(Iterable<Variable> loopAssigned,
+      Iterable<Variable> loopCaptured, Variable loopVariable) {
+    _SimpleStatementContext<Variable, Type> context =
+        new _SimpleStatementContext<Variable, Type>(_current);
+    _stack.add(context);
+    _current = _current.removePromotedAll(loopAssigned, loopCaptured);
+    if (loopVariable != null) {
+      _current = _current.write(loopVariable);
+    }
+  }
+
+  @override
+  void forEach_end() {
+    _SimpleStatementContext<Variable, Type> context =
+        _stack.removeLast() as _SimpleStatementContext<Variable, Type>;
+    _current = _join(_current, context._previous);
+  }
+
+  @override
+  void functionExpression_begin(Iterable<Variable> writeCaptured) {
+    ++_functionNestingLevel;
+    _current = _current.removePromotedAll(const [], writeCaptured);
+    _stack.add(new _SimpleContext(_current));
+    _current = _current.removePromotedAll(
+        _variablesWrittenAnywhere, _variablesCapturedAnywhere);
+  }
+
+  @override
+  void functionExpression_end() {
+    --_functionNestingLevel;
+    assert(_functionNestingLevel >= 0);
+    _SimpleContext<Variable, Type> context =
+        _stack.removeLast() as _SimpleContext<Variable, Type>;
+    _current = context._previous;
+  }
+
+  @override
+  void handleBreak(Statement target) {
+    _BranchTargetContext<Variable, Type> context = _statementToContext[target];
+    if (context != null) {
+      context._breakModel = _join(context._breakModel, _current);
+    }
+    _current = _current.setReachable(false);
+  }
+
+  @override
+  void handleContinue(Statement target) {
+    _BranchTargetContext<Variable, Type> context = _statementToContext[target];
+    if (context != null) {
+      context._continueModel = _join(context._continueModel, _current);
+    }
+    _current = _current.setReachable(false);
+  }
+
+  @override
+  void handleExit() {
+    _current = _current.setReachable(false);
+  }
+
+  @override
+  void ifNullExpression_end() {
+    _SimpleContext<Variable, Type> context =
+        _stack.removeLast() as _SimpleContext<Variable, Type>;
+    _current = _join(_current, context._previous);
+  }
+
+  @override
+  void ifNullExpression_rightBegin() {
+    _stack.add(new _SimpleContext<Variable, Type>(_current));
+  }
+
+  @override
+  void ifStatement_elseBegin() {
+    _IfContext<Variable, Type> context =
+        _stack.last as _IfContext<Variable, Type>;
+    context._afterThen = _current;
+    _current = context._conditionInfo._ifFalse;
+  }
+
+  @override
+  void ifStatement_end(bool hasElse) {
+    _IfContext<Variable, Type> context =
+        _stack.removeLast() as _IfContext<Variable, Type>;
+    FlowModel<Variable, Type> afterThen;
+    FlowModel<Variable, Type> afterElse;
+    if (hasElse) {
+      afterThen = context._afterThen;
+      afterElse = _current;
+    } else {
+      afterThen = _current; // no `else`, so `then` is still current
+      afterElse = context._conditionInfo._ifFalse;
+    }
+    _current = _join(afterThen, afterElse);
+  }
+
+  @override
+  void ifStatement_thenBegin(Expression condition) {
+    _ExpressionInfo<Variable, Type> conditionInfo = _expressionEnd(condition);
+    _stack.add(new _IfContext(conditionInfo));
+    _current = conditionInfo._ifTrue;
+  }
+
+  @override
+  void initialize(Variable variable) {
+    _current = _current.write(variable);
+  }
+
+  @override
+  bool isAssigned(Variable variable) {
+    return _current.infoFor(variable).assigned;
+  }
+
+  @override
+  void isExpression_end(
+      Expression isExpression, Variable variable, bool isNot, Type type) {
+    FlowModel<Variable, Type> promoted =
+        _current.promote(typeOperations, variable, type);
+    _storeExpressionInfo(
+        isExpression,
+        isNot
+            ? new _ExpressionInfo(_current, _current, promoted)
+            : new _ExpressionInfo(_current, promoted, _current));
+  }
+
+  @override
+  void logicalBinaryOp_end(Expression wholeExpression, Expression rightOperand,
+      {@required bool isAnd}) {
+    _BranchContext<Variable, Type> context =
+        _stack.removeLast() as _BranchContext<Variable, Type>;
+    _ExpressionInfo<Variable, Type> rhsInfo = _expressionEnd(rightOperand);
+
+    FlowModel<Variable, Type> trueResult;
+    FlowModel<Variable, Type> falseResult;
+    if (isAnd) {
+      trueResult = rhsInfo._ifTrue;
+      falseResult = _join(context._conditionInfo._ifFalse, rhsInfo._ifFalse);
+    } else {
+      trueResult = _join(context._conditionInfo._ifTrue, rhsInfo._ifTrue);
+      falseResult = rhsInfo._ifFalse;
+    }
+    _storeExpressionInfo(
+        wholeExpression,
+        new _ExpressionInfo(
+            _join(trueResult, falseResult), trueResult, falseResult));
+  }
+
+  @override
+  void logicalBinaryOp_rightBegin(Expression leftOperand,
+      {@required bool isAnd}) {
+    _ExpressionInfo<Variable, Type> conditionInfo = _expressionEnd(leftOperand);
+    _stack.add(new _BranchContext<Variable, Type>(conditionInfo));
+    _current = isAnd ? conditionInfo._ifTrue : conditionInfo._ifFalse;
+  }
+
+  @override
+  void logicalNot_end(Expression notExpression, Expression operand) {
+    _ExpressionInfo<Variable, Type> conditionInfo = _expressionEnd(operand);
+    _storeExpressionInfo(
+        notExpression,
+        new _ExpressionInfo(conditionInfo._after, conditionInfo._ifFalse,
+            conditionInfo._ifTrue));
+  }
+
+  @override
+  void nonNullAssert_end(Expression operand) {
+    _ExpressionInfo<Variable, Type> operandInfo = _getExpressionInfo(operand);
+    if (operandInfo is _VariableReadInfo<Variable, Type>) {
+      _current =
+          _current.markNonNullable(typeOperations, operandInfo._variable);
+    }
+  }
+
+  @override
+  void nullLiteral(Expression expression) {
+    _storeExpressionInfo(expression, new _NullInfo(_current));
+  }
+
+  @override
+  void parenthesizedExpression(
+      Expression outerExpression, Expression innerExpression) {
+    if (identical(_expressionWithInfo, innerExpression)) {
+      _expressionWithInfo = outerExpression;
+    }
+  }
+
+  @override
+  Type promotedType(Variable variable) {
+    return _current.infoFor(variable).promotedType;
+  }
+
+  @override
+  void switchStatement_beginCase(bool hasLabel, Iterable<Variable> notPromoted,
+      Iterable<Variable> captured) {
+    _SimpleStatementContext<Variable, Type> context =
+        _stack.last as _SimpleStatementContext<Variable, Type>;
+    if (hasLabel) {
+      _current = context._previous.removePromotedAll(notPromoted, captured);
+    } else {
+      _current = context._previous;
+    }
+  }
+
+  @override
+  void switchStatement_end(bool hasDefault) {
+    _SimpleStatementContext<Variable, Type> context =
+        _stack.removeLast() as _SimpleStatementContext<Variable, Type>;
+    FlowModel<Variable, Type> breakState = context._breakModel;
+
+    // It is allowed to "fall off" the end of a switch statement, so join the
+    // current state to any breaks that were found previously.
+    breakState = _join(breakState, _current);
+
+    // And, if there is an implicit fall-through default, join it to any breaks.
+    if (!hasDefault) breakState = _join(breakState, context._previous);
+
+    _current = breakState;
+  }
+
+  @override
+  void switchStatement_expressionEnd(Statement switchStatement) {
+    _SimpleStatementContext<Variable, Type> context =
+        new _SimpleStatementContext<Variable, Type>(_current);
+    _stack.add(context);
+    _statementToContext[switchStatement] = context;
+  }
+
+  @override
+  void tryCatchStatement_bodyBegin() {
+    _stack.add(new _TryContext<Variable, Type>(_current));
+  }
+
+  @override
+  void tryCatchStatement_bodyEnd(
+      Iterable<Variable> assignedInBody, Iterable<Variable> capturedInBody) {
+    _TryContext<Variable, Type> context =
+        _stack.last as _TryContext<Variable, Type>;
+    FlowModel<Variable, Type> beforeBody = context._previous;
+    FlowModel<Variable, Type> beforeCatch =
+        beforeBody.removePromotedAll(assignedInBody, capturedInBody);
+    context._beforeCatch = beforeCatch;
+    context._afterBodyAndCatches = _current;
+  }
+
+  @override
+  void tryCatchStatement_catchBegin() {
+    _TryContext<Variable, Type> context =
+        _stack.last as _TryContext<Variable, Type>;
+    _current = context._beforeCatch;
+  }
+
+  @override
+  void tryCatchStatement_catchEnd() {
+    _TryContext<Variable, Type> context =
+        _stack.last as _TryContext<Variable, Type>;
+    context._afterBodyAndCatches =
+        _join(context._afterBodyAndCatches, _current);
+  }
+
+  @override
+  void tryCatchStatement_end() {
+    _TryContext<Variable, Type> context =
+        _stack.removeLast() as _TryContext<Variable, Type>;
+    _current = context._afterBodyAndCatches;
+  }
+
+  @override
+  void tryFinallyStatement_bodyBegin() {
+    _stack.add(new _TryContext<Variable, Type>(_current));
+  }
+
+  @override
+  void tryFinallyStatement_end(Set<Variable> assignedInFinally) {
+    _TryContext<Variable, Type> context =
+        _stack.removeLast() as _TryContext<Variable, Type>;
+    _current = _current.restrict(
+        typeOperations, context._afterBodyAndCatches, assignedInFinally);
+  }
+
+  @override
+  void tryFinallyStatement_finallyBegin(
+      Iterable<Variable> assignedInBody, Iterable<Variable> capturedInBody) {
+    _TryContext<Variable, Type> context =
+        _stack.last as _TryContext<Variable, Type>;
+    context._afterBodyAndCatches = _current;
+    _current = _join(_current,
+        context._previous.removePromotedAll(assignedInBody, capturedInBody));
+  }
+
+  @override
+  Type variableRead(Expression expression, Variable variable) {
+    _storeExpressionInfo(expression, new _VariableReadInfo(_current, variable));
+    return _current.infoFor(variable).promotedType;
+  }
+
+  @override
+  void whileStatement_bodyBegin(
+      Statement whileStatement, Expression condition) {
+    _ExpressionInfo<Variable, Type> conditionInfo = _expressionEnd(condition);
+    _WhileContext<Variable, Type> context =
+        new _WhileContext<Variable, Type>(conditionInfo);
+    _stack.add(context);
+    _statementToContext[whileStatement] = context;
+    _current = conditionInfo._ifTrue;
+  }
+
+  @override
+  void whileStatement_conditionBegin(
+      Iterable<Variable> loopAssigned, Iterable<Variable> loopCaptured) {
+    _current = _current.removePromotedAll(loopAssigned, loopCaptured);
+  }
+
+  @override
+  void whileStatement_end() {
+    _WhileContext<Variable, Type> context =
+        _stack.removeLast() as _WhileContext<Variable, Type>;
+    _current = _join(context._conditionInfo._ifFalse, context._breakModel);
+  }
+
+  @override
+  void write(Variable variable) {
+    assert(
+        _variablesWrittenAnywhere.contains(variable),
+        "Variable is written to, but was not included in "
+        "_variablesWrittenAnywhere: $variable");
+    _current = _current.write(variable);
+  }
+
+  /// Gets the [_ExpressionInfo] associated with the [expression] (which should
+  /// be the last expression that was traversed).  If there is no
+  /// [_ExpressionInfo] associated with the [expression], then a fresh
+  /// [_ExpressionInfo] is created recording the current flow analysis state.
+  _ExpressionInfo<Variable, Type> _expressionEnd(Expression expression) =>
+      _getExpressionInfo(expression) ??
+      new _ExpressionInfo(_current, _current, _current);
+
+  /// Gets the [_ExpressionInfo] associated with the [expression] (which should
+  /// be the last expression that was traversed).  If there is no
+  /// [_ExpressionInfo] associated with the [expression], then `null` is
+  /// returned.
+  _ExpressionInfo<Variable, Type> _getExpressionInfo(Expression expression) {
+    if (identical(expression, _expressionWithInfo)) {
+      _ExpressionInfo<Variable, Type> expressionInfo = _expressionInfo;
+      _expressionInfo = null;
+      return expressionInfo;
+    } else {
+      return null;
+    }
+  }
+
+  FlowModel<Variable, Type> _join(
+          FlowModel<Variable, Type> first, FlowModel<Variable, Type> second) =>
+      FlowModel.join(typeOperations, first, second);
+
+  /// Associates [expression], which should be the most recently visited
+  /// expression, with the given [expressionInfo] object, and updates the
+  /// current flow model state to correspond to it.
+  void _storeExpressionInfo(
+      Expression expression, _ExpressionInfo<Variable, Type> expressionInfo) {
+    _expressionWithInfo = expression;
+    _expressionInfo = expressionInfo;
+    _current = expressionInfo._after;
+  }
+}
+
+/// Base class for objects representing constructs in the Dart programming
+/// language for which flow analysis information needs to be tracked.
+class _FlowContext {}
+
+/// [_FlowContext] representing an `if` statement.
+class _IfContext<Variable, Type> extends _BranchContext<Variable, Type> {
+  /// Flow model associated with the state of program execution after the `if`
+  /// statement executes, in the circumstance where the "then" branch is taken.
+  FlowModel<Variable, Type> _afterThen;
+
+  _IfContext(_ExpressionInfo<Variable, Type> conditionInfo)
+      : super(conditionInfo);
+}
+
+/// [_ExpressionInfo] representing a `null` literal.
+class _NullInfo<Variable, Type> implements _ExpressionInfo<Variable, Type> {
+  @override
+  final FlowModel<Variable, Type> _after;
+
+  _NullInfo(this._after);
+
+  @override
+  FlowModel<Variable, Type> get _ifFalse => _after;
+
+  @override
+  FlowModel<Variable, Type> get _ifTrue => _after;
+}
+
+/// [_FlowContext] representing a language construct for which flow analysis
+/// must store a flow model state to be retrieved later, such as a `try`
+/// statement, function expression, or "if-null" (`??`) expression.
+class _SimpleContext<Variable, Type> extends _FlowContext {
+  /// The stored state.  For a `try` statement, this is the state from the
+  /// beginning of the `try` block.  For a function expression, this is the
+  /// state at the point the function expression was created.  For an "if-null"
+  /// expression, this is the state after execution of the expression before the
+  /// `??`.
+  final FlowModel<Variable, Type> _previous;
+
+  _SimpleContext(this._previous);
+}
+
+/// [_FlowContext] representing a language construct that can be targeted by
+/// `break` or `continue` statements, and for which flow analysis must store a
+/// flow model state to be retrieved later.  Examples include "for each" and
+/// `switch` statements.
+class _SimpleStatementContext<Variable, Type>
+    extends _BranchTargetContext<Variable, Type> {
+  /// The stored state.  For a "for each" statement, this is the state after
+  /// evaluation of the iterable.  For a `switch` statement, this is the state
+  /// after evaluation of the switch expression.
+  final FlowModel<Variable, Type> _previous;
+
+  _SimpleStatementContext(this._previous);
+}
+
+/// [_FlowContext] representing a try statement.
+class _TryContext<Variable, Type> extends _SimpleContext<Variable, Type> {
+  /// If the statement is a "try/catch" statement, the flow model representing
+  /// program state at the top of any `catch` block.
+  FlowModel<Variable, Type> _beforeCatch;
+
+  /// If the statement is a "try/catch" statement, the accumulated flow model
+  /// representing program state after the `try` block or one of the `catch`
+  /// blocks has finished executing.  If the statement is a "try/finally"
+  /// statement, the flow model representing program state after the `try` block
+  /// has finished executing.
+  FlowModel<Variable, Type> _afterBodyAndCatches;
+
+  _TryContext(FlowModel<Variable, Type> previous) : super(previous);
+}
+
+/// [_ExpressionInfo] representing an expression that reads the value of a
+/// variable.
+class _VariableReadInfo<Variable, Type>
+    implements _ExpressionInfo<Variable, Type> {
+  @override
+  final FlowModel<Variable, Type> _after;
+
+  /// The variable that is being read.
+  final Variable _variable;
+
+  _VariableReadInfo(this._after, this._variable);
+
+  @override
+  FlowModel<Variable, Type> get _ifFalse => _after;
+
+  @override
+  FlowModel<Variable, Type> get _ifTrue => _after;
+}
+
+/// [_FlowContext] representing a `while` loop (or a C-style `for` loop, which
+/// is functionally similar).
+class _WhileContext<Variable, Type>
+    extends _BranchTargetContext<Variable, Type> {
+  /// Flow models associated with the loop condition.
+  final _ExpressionInfo<Variable, Type> _conditionInfo;
+
+  _WhileContext(this._conditionInfo);
+}
diff --git a/pkg/front_end/lib/src/fasta/import.dart b/pkg/front_end/lib/src/fasta/import.dart
index 437ec72..8707e2c 100644
--- a/pkg/front_end/lib/src/fasta/import.dart
+++ b/pkg/front_end/lib/src/fasta/import.dart
@@ -6,9 +6,9 @@
 
 import 'package:kernel/ast.dart' show LibraryDependency;
 
-import 'builder/builder.dart' show Builder, LibraryBuilder;
-
-import 'builder/prefix_builder.dart' show PrefixBuilder;
+import 'builder/builder.dart';
+import 'builder/library_builder.dart';
+import 'builder/prefix_builder.dart';
 
 import 'kernel/kernel_builder.dart' show toKernelCombinators;
 
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index 61e208b..891567a0 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -14,7 +14,8 @@
         BinaryBuilderWithMetadata,
         CanonicalNameError,
         CanonicalNameSdkError,
-        InvalidKernelVersionError;
+        InvalidKernelVersionError,
+        SubComponentView;
 
 import 'package:kernel/class_hierarchy.dart'
     show ClassHierarchy, ClosedWorldClassHierarchy;
@@ -49,7 +50,9 @@
 
 import '../api_prototype/memory_file_system.dart' show MemoryFileSystem;
 
-import 'builder/builder.dart' show Builder, ClassBuilder, LibraryBuilder;
+import 'builder/builder.dart';
+import 'builder/class_builder.dart';
+import 'builder/library_builder.dart';
 
 import 'builder_graph.dart' show BuilderGraph;
 
@@ -61,6 +64,8 @@
 
 import 'dill/dill_target.dart' show DillTarget;
 
+import 'incremental_serializer.dart' show IncrementalSerializer;
+
 import 'util/error_reporter_file_copier.dart' show saveAsGzip;
 
 import 'fasta_codes.dart'
@@ -106,6 +111,7 @@
   final Uri initializeFromDillUri;
   final Component componentToInitializeFrom;
   bool initializedFromDill = false;
+  bool initializedIncrementalSerializer = false;
   Uri previousPackagesUri;
   Map<String, Uri> previousPackagesMap;
   Map<String, Uri> currentPackagesMap;
@@ -113,6 +119,7 @@
   Map<Uri, List<DiagnosticMessageFromJson>> remainingComponentProblems =
       new Map<Uri, List<DiagnosticMessageFromJson>>();
   List<Component> modulesToLoad;
+  IncrementalSerializer incrementalSerializer;
 
   static final Uri debugExprUri =
       new Uri(scheme: "org-dartlang-debug", path: "synthetic_debug_expression");
@@ -121,16 +128,20 @@
 
   IncrementalCompiler.fromComponent(
       this.context, Component this.componentToInitializeFrom,
-      [bool outlineOnly])
+      [bool outlineOnly, IncrementalSerializer incrementalSerializer])
       : ticker = context.options.ticker,
         initializeFromDillUri = null,
-        this.outlineOnly = outlineOnly ?? false;
+        this.outlineOnly = outlineOnly ?? false,
+        this.incrementalSerializer = incrementalSerializer;
 
   IncrementalCompiler(this.context,
-      [this.initializeFromDillUri, bool outlineOnly])
+      [this.initializeFromDillUri,
+      bool outlineOnly,
+      IncrementalSerializer incrementalSerializer])
       : ticker = context.options.ticker,
         componentToInitializeFrom = null,
-        this.outlineOnly = outlineOnly ?? false;
+        this.outlineOnly = outlineOnly ?? false,
+        this.incrementalSerializer = incrementalSerializer;
 
   @override
   Future<Component> computeDelta(
@@ -238,7 +249,9 @@
 
       bool removedDillBuilders = false;
       for (LibraryBuilder builder in notReusedLibraries) {
-        CompilerContext.current.uriToSource.remove(builder.fileUri);
+        cleanupSourcesForBuilder(
+            builder, uriTranslator, CompilerContext.current.uriToSource);
+        incrementalSerializer?.invalidate(builder.fileUri);
 
         LibraryBuilder dillBuilder =
             dillLoadedData.loader.builders.remove(builder.uri);
@@ -672,6 +685,7 @@
     }
 
     LibraryGraph graph = new LibraryGraph(libraryMap);
+    Set<Uri> partsUsed = new Set<Uri>();
     while (worklist.isNotEmpty && potentiallyReferencedLibraries.isNotEmpty) {
       Uri uri = worklist.removeLast();
       if (libraryMap.containsKey(uri)) {
@@ -685,6 +699,12 @@
           if (potentiallyReferencedInputLibraries.remove(uri) != null) {
             inputLibrariesFiltered?.add(library);
           }
+          for (LibraryPart part in library.parts) {
+            Uri partFileUri =
+                getPartFileUri(library.fileUri, part, uriTranslator);
+            partsUsed.add(partFileUri);
+          }
+          partsUsed;
         }
       }
     }
@@ -697,10 +717,14 @@
         Library lib = builder.library;
         removedLibraries.add(lib);
         dillLoadedData.loader.builders.remove(uri);
-        CompilerContext.current.uriToSource.remove(uri);
-        uriToSource.remove(uri);
+        cleanupSourcesForBuilder(builder, uriTranslator,
+            CompilerContext.current.uriToSource, uriToSource, partsUsed);
         userBuilders?.remove(uri);
-        removeLibraryFromRemainingComponentProblems(lib, uriTranslator);
+        removeLibraryFromRemainingComponentProblems(
+            lib, uriTranslator, partsUsed);
+
+        // Technically this isn't necessary as the uri is not a package-uri.
+        incrementalSerializer?.invalidate(builder.fileUri);
       }
     }
     hierarchy?.applyTreeChanges(removedLibraries, const []);
@@ -709,8 +733,32 @@
   }
 
   /// Internal method.
+  ///
+  /// [partsUsed] indicates part uris that are used by (other/alive) libraries.
+  /// Those parts will not be cleaned up. This is useful when a part has been
+  /// "moved" to be part of another library.
+  void cleanupSourcesForBuilder(LibraryBuilder builder,
+      UriTranslator uriTranslator, Map<Uri, Source> uriToSource,
+      [Map<Uri, Source> uriToSourceExtra, Set<Uri> partsUsed]) {
+    uriToSource.remove(builder.fileUri);
+    uriToSourceExtra?.remove(builder.fileUri);
+    Library lib = builder.library;
+    for (LibraryPart part in lib.parts) {
+      Uri partFileUri = getPartFileUri(lib.fileUri, part, uriTranslator);
+      if (partsUsed != null && partsUsed.contains(partFileUri)) continue;
+      uriToSource.remove(partFileUri);
+      uriToSourceExtra?.remove(partFileUri);
+    }
+  }
+
+  /// Internal method.
+  ///
+  /// [partsUsed] indicates part uris that are used by (other/alive) libraries.
+  /// Those parts will not be removed from the component problems.
+  /// This is useful when a part has been "moved" to be part of another library.
   void removeLibraryFromRemainingComponentProblems(
-      Library lib, UriTranslator uriTranslator) {
+      Library lib, UriTranslator uriTranslator,
+      [Set<Uri> partsUsed]) {
     remainingComponentProblems.remove(lib.fileUri);
     // Remove parts too.
     for (LibraryPart part in lib.parts) {
@@ -753,9 +801,14 @@
 
         // We're going to output all we read here so lazy loading it
         // doesn't make sense.
-        new BinaryBuilderWithMetadata(initializationBytes,
+        List<SubComponentView> views = new BinaryBuilderWithMetadata(
+                initializationBytes,
                 disableLazyReading: true)
-            .readComponent(data.component, checkCanonicalNames: true);
+            .readComponent(data.component,
+                checkCanonicalNames: true, createView: true);
+        initializedIncrementalSerializer =
+            incrementalSerializer?.initialize(initializationBytes, views) ??
+                false;
 
         // Check the any package-urls still point to the same file
         // (e.g. the package still exists and hasn't been updated).
diff --git a/pkg/front_end/lib/src/fasta/incremental_serializer.dart b/pkg/front_end/lib/src/fasta/incremental_serializer.dart
new file mode 100644
index 0000000..59d8488
--- /dev/null
+++ b/pkg/front_end/lib/src/fasta/incremental_serializer.dart
@@ -0,0 +1,349 @@
+// 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 fasta.incremental_serializer;
+
+import 'dart:typed_data' show Uint8List;
+
+import 'package:kernel/binary/ast_from_binary.dart' show SubComponentView;
+
+import 'package:kernel/binary/ast_to_binary.dart' show BinaryPrinter;
+
+import 'package:kernel/kernel.dart' show Component, Library, LibraryDependency;
+
+import 'kernel/utils.dart' show ByteSink;
+
+class IncrementalSerializer {
+  final Map<Uri, SerializationGroup> uriToGroup =
+      new Map<Uri, SerializationGroup>();
+  final Set<Uri> invalidatedUris = new Set<Uri>();
+
+  /// Invalidate the uri: Will remove cache associated with it, depending on it
+  /// etc. Called by the incremental compiler.
+  void invalidate(Uri uri) {
+    invalidatedUris.add(uri);
+  }
+
+  /// Initializes the cache via a already serialized list of bytes based on the
+  /// view of those bytes. Called by the incremental compiler.
+  bool initialize(List<int> bytes, List<SubComponentView> views) {
+    if (uriToGroup.isNotEmpty) {
+      throw "Cannot initialize when already in use.";
+    }
+
+    // Find the sub-components that are packaged correctly.
+    List<SubComponentView> goodViews = [];
+    Set<Uri> uris = new Set<Uri>();
+    for (int i = 0; i < views.length; i++) {
+      SubComponentView view = views[i];
+      bool good = true;
+      String packageName;
+      for (Library lib in view.libraries) {
+        Uri uri = lib.importUri;
+        // Uris need to be unique.
+        if (!uris.add(lib.fileUri)) return false;
+        if (uri.scheme == "package") {
+          String thisPackageName = uri.pathSegments.first;
+          if (packageName == null) {
+            packageName = thisPackageName;
+          } else if (packageName != thisPackageName) {
+            good = false;
+          }
+        } else {
+          good = false;
+        }
+      }
+      if (good) {
+        goodViews.add(view);
+      }
+    }
+
+    // Add groups. Wrap in try because an exception will be thrown if a group
+    // has a dependency that isn't being met.
+    try {
+      List<SerializationGroup> newGroups = new List<SerializationGroup>();
+      for (int i = 0; i < goodViews.length; i++) {
+        SubComponentView view = goodViews[i];
+        List<int> data = new Uint8List(view.componentFileSize);
+        data.setRange(0, data.length, bytes, view.componentStartOffset);
+        SerializationGroup newGroup = createGroupFor(view.libraries, data);
+        newGroups.add(newGroup);
+      }
+
+      // Setup dependency tracking for the new groups.
+      for (int i = 0; i < goodViews.length; i++) {
+        SubComponentView view = goodViews[i];
+        List<Library> libraries = view.libraries;
+        SerializationGroup packageGroup = newGroups[i];
+        setupDependencyTracking(libraries, packageGroup);
+      }
+    } catch (e) {
+      uriToGroup.clear();
+      return false;
+    }
+    return true;
+  }
+
+  /// Write packages to sink, cache new package data, trim input component.
+  void writePackagesToSinkAndTrimComponent(
+      Component component, Sink<List<int>> sink) {
+    if (component == null) return;
+    if (component.libraries.isEmpty) return;
+
+    // If we're given a partial component (i.e. an actual delta component)
+    // incremental serialization (at least currently) doesn't work.
+    // The reason is that it might contain a new partial thing of what we
+    // already have cached while still depending on something from the same
+    // group that is currently cached. We would throw away the cache, but
+    // actually depend on something we just threw away --- we would try to
+    // include it and crash because we no longer have it.
+    // Alternative ways to fix this could be:
+    // * to group into smaller groups so this wouldn't happen.
+    // * cache the actual Libraries too, so we could re-serialize when needed
+    //   (though maybe not eagerly).
+    if (!isSelfContained(component)) return;
+
+    // Remove cache pertaining to invalidated uris.
+    if (invalidatedUris.isNotEmpty) {
+      removeInvalidated();
+    }
+
+    // Make sure we can serialize individual libraries.
+    component.computeCanonicalNames();
+
+    // Split into package and non-package libraries.
+    List<Library> packageLibraries = new List<Library>();
+    List<Library> nonPackageLibraries = new List<Library>();
+    for (Library lib in component.libraries) {
+      Uri uri = lib.importUri;
+      if (uri.scheme == "package") {
+        packageLibraries.add(lib);
+      } else {
+        nonPackageLibraries.add(lib);
+      }
+    }
+
+    // Output already serialized packages and group needed non-serialized
+    // packages.
+    Map<String, List<Library>> newPackages = new Map<String, List<Library>>();
+    Set<SerializationGroup> cachedPackagesInOutput =
+        new Set<SerializationGroup>.identity();
+    for (Library lib in packageLibraries) {
+      SerializationGroup group = uriToGroup[lib.fileUri];
+      if (group != null) {
+        addDataButNotDependentData(group, cachedPackagesInOutput, sink);
+      } else {
+        String package = lib.importUri.pathSegments.first;
+        newPackages[package] ??= <Library>[];
+        newPackages[package].add(lib);
+      }
+    }
+
+    // Add any dependencies that wasn't added already.
+    List<SerializationGroup> upFrontGroups = cachedPackagesInOutput.toList();
+    for (SerializationGroup group in upFrontGroups) {
+      if (group.dependencies != null) {
+        // Now also add all dependencies.
+        for (SerializationGroup dep in group.dependencies) {
+          addDataAndDependentData(dep, cachedPackagesInOutput, sink);
+        }
+      }
+    }
+
+    // Serialize all new packages, create groups and add to sink.
+    Map<String, SerializationGroup> newPackageGroups =
+        new Map<String, SerializationGroup>();
+    for (String package in newPackages.keys) {
+      List<Library> libraries = newPackages[package];
+      List<int> data = serialize(component, libraries);
+      sink.add(data);
+      SerializationGroup newGroup = createGroupFor(libraries, data);
+      newPackageGroups[package] = newGroup;
+    }
+
+    // Setup dependency tracking for the new groups.
+    for (String package in newPackages.keys) {
+      List<Library> libraries = newPackages[package];
+      SerializationGroup packageGroup = newPackageGroups[package];
+      setupDependencyTracking(libraries, packageGroup);
+    }
+
+    // All packages have been added to the sink already.
+    component.libraries
+      ..clear()
+      ..addAll(nonPackageLibraries);
+  }
+
+  bool isSelfContained(Component component) {
+    Set<Library> got = new Set<Library>.from(component.libraries);
+    for (Library lib in component.libraries) {
+      for (LibraryDependency dependency in lib.dependencies) {
+        if (!got.contains(dependency.targetLibrary)) {
+          if (dependency.targetLibrary.importUri.scheme == "dart") {
+            continue;
+          }
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
+  /// Remove cached data based on what has been invalidated.
+  /// Note that invalidating a single file can remove many cached things because
+  /// of dependencies.
+  void removeInvalidated() {
+    // Remove all directly invalidated entries.
+    Set<SerializationGroup> removed = new Set<SerializationGroup>();
+    List<SerializationGroup> workList = new List<SerializationGroup>();
+    for (Uri uri in invalidatedUris) {
+      removeUriFromMap(uri, removed, workList);
+    }
+
+    // Continuously remove all that depend on the removed groups.
+    //
+    // Note that with the current invalidating strategy in the incremental
+    // compiler this is not strictly necessary (assuming the incremental
+    // compiler is used via the incremental compiler) - but it is included for
+    // completeness.
+    //
+    // The reason we have to do this (assuming a different incremental
+    // compiler invalidation strategy), is that we group things into packages,
+    // meaning that a group as a whole might depend on another group containing
+    // libraries that is not in the input component. Not removing these groups
+    // could lead to including a group in an output where we cannot re-create
+    // the dependencies. Example:
+    // Group #1: [lib1]
+    // Group #2: [lib2, lib3]. Note that lib3 depends on lib1, but lib2 is
+    //                         standalone.
+    // Lib1 is invalidated and we thus remove group #1.
+    // We then serialize something that needs lib2. We thus output group #2.
+    // We should now also output group #1, but we don't have it so we can't.
+    // We can't re-create it either, because the input component only contains
+    // lib2 as it is standalone. Had we removed group #2 too everything would
+    // have been fine as we would then just serialize and cached lib2 by itself.
+    while (workList.isNotEmpty) {
+      SerializationGroup group = workList.removeLast();
+      if (group.othersDependingOnMe == null) continue;
+      for (SerializationGroup dependsOnGroup in group.othersDependingOnMe) {
+        removeUriFromMap(dependsOnGroup.uris.first, removed, workList);
+      }
+    }
+
+    invalidatedUris.clear();
+  }
+
+  /// Setup dependency tracking for a single group having the specified
+  /// libraries. Note that all groups this depend on has to be created prior
+  /// to calling this.
+  void setupDependencyTracking(
+      List<Library> libraries, SerializationGroup packageGroup) {
+    for (Library lib in libraries) {
+      for (LibraryDependency dep in lib.dependencies) {
+        Library dependencyLibrary = dep.importedLibraryReference.asLibrary;
+        if (dependencyLibrary.importUri.scheme != "package") continue;
+        Uri dependencyLibraryUri =
+            dep.importedLibraryReference.asLibrary.fileUri;
+        SerializationGroup depGroup = uriToGroup[dependencyLibraryUri];
+        if (depGroup == null) {
+          throw "Didn't contain group for $dependencyLibraryUri";
+        }
+        if (depGroup == packageGroup) continue;
+        packageGroup.registerDependency(depGroup);
+      }
+    }
+  }
+
+  /// Add the group but not its dependencies to the output if they weren't added
+  /// already.
+  addDataButNotDependentData(SerializationGroup group,
+      Set<SerializationGroup> cachedPackagesInOutput, Sink<List<int>> sink) {
+    if (cachedPackagesInOutput.add(group)) {
+      sink.add(group.serializedData);
+    }
+  }
+
+  /// Add the group and its dependencies to the output if they weren't added
+  /// already.
+  addDataAndDependentData(SerializationGroup group,
+      Set<SerializationGroup> cachedPackagesInOutput, Sink<List<int>> sink) {
+    if (cachedPackagesInOutput.add(group)) {
+      sink.add(group.serializedData);
+      if (group.dependencies != null) {
+        // Now also add all dependencies.
+        for (SerializationGroup dep in group.dependencies) {
+          addDataAndDependentData(dep, cachedPackagesInOutput, sink);
+        }
+      }
+    }
+  }
+
+  /// Create a [SerializationGroup] for the input, setting up [uriToGroup].
+  SerializationGroup createGroupFor(List<Library> libraries, List<int> data) {
+    Set<Uri> libraryUris = new Set<Uri>();
+    for (Library lib in libraries) {
+      libraryUris.add(lib.fileUri);
+    }
+
+    SerializationGroup newGroup = new SerializationGroup(data, libraryUris);
+
+    for (Uri uri in libraryUris) {
+      assert(!uriToGroup.containsKey(uri));
+      uriToGroup[uri] = newGroup;
+    }
+    return newGroup;
+  }
+
+  /// Serialize the specified libraries using other needed data from the
+  /// component.
+  List<int> serialize(Component component, List<Library> libraries) {
+    Component singlePackageLibraries = new Component(
+        libraries: libraries,
+        uriToSource: component.uriToSource,
+        nameRoot: component.root);
+
+    ByteSink byteSink = new ByteSink();
+    final BinaryPrinter printer = new BinaryPrinter(byteSink);
+    printer.writeComponentFile(singlePackageLibraries);
+    return byteSink.builder.takeBytes();
+  }
+
+  /// Remove the specified uri from the [uriToGroup] map.
+  ///
+  /// Also remove all uris in the group the uri belongs to, and add the group to
+  /// the worklist.
+  void removeUriFromMap(Uri uri, Set<SerializationGroup> removed,
+      List<SerializationGroup> workList) {
+    SerializationGroup group = uriToGroup.remove(uri);
+    if (group == null) return;
+    bool added = removed.add(group);
+    assert(added);
+    workList.add(group);
+    for (Uri groupUri in group.uris) {
+      SerializationGroup sameGroup = uriToGroup.remove(groupUri);
+      assert((groupUri == uri && sameGroup == null) ||
+          (groupUri != uri && sameGroup != null));
+    }
+  }
+}
+
+class SerializationGroup {
+  final List<int> serializedData;
+  final Set<Uri> uris;
+  Set<SerializationGroup> dependencies;
+  Set<SerializationGroup> othersDependingOnMe;
+
+  SerializationGroup(this.serializedData, this.uris);
+
+  /// Register the dependency that this group depends on the [other] one.
+  /// The registration is bilateral so that [other] is added as a dependency for
+  /// this, and this is added as a "others depend on me" for [other].
+  void registerDependency(SerializationGroup other) {
+    dependencies ??= new Set<SerializationGroup>.identity();
+    if (dependencies.add(other)) {
+      other.othersDependingOnMe ??= new Set<SerializationGroup>.identity();
+      other.othersDependingOnMe.add(this);
+    }
+  }
+}
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 b69ed51..8f24710 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -9,11 +9,29 @@
 import 'package:kernel/ast.dart';
 import 'package:kernel/type_environment.dart';
 
-import '../builder/declaration.dart';
-
+import '../builder/builder.dart';
+import '../builder/class_builder.dart';
+import '../builder/constructor_builder.dart';
 import '../builder/declaration_builder.dart';
-
+import '../builder/enum_builder.dart';
 import '../builder/extension_builder.dart';
+import '../builder/field_builder.dart';
+import '../builder/formal_parameter_builder.dart';
+import '../builder/function_builder.dart';
+import '../builder/function_type_builder.dart';
+import '../builder/invalid_type_declaration_builder.dart';
+import '../builder/library_builder.dart';
+import '../builder/member_builder.dart';
+import '../builder/modifier_builder.dart';
+import '../builder/named_type_builder.dart';
+import '../builder/nullability_builder.dart';
+import '../builder/prefix_builder.dart';
+import '../builder/procedure_builder.dart';
+import '../builder/type_builder.dart';
+import '../builder/type_declaration_builder.dart';
+import '../builder/type_variable_builder.dart';
+import '../builder/unresolved_type.dart';
+import '../builder/void_type_builder.dart';
 
 import '../constant_context.dart' show ConstantContext;
 
@@ -23,6 +41,14 @@
 
 import '../fasta_codes.dart' show LocatedMessage, Message, noLength, Template;
 
+import '../identifiers.dart'
+    show
+        Identifier,
+        InitializedIdentifier,
+        QualifiedName,
+        deprecated_extractToken,
+        flattenName;
+
 import '../messages.dart' as messages show getLocationFromUri;
 
 import '../modifier.dart'
@@ -59,7 +85,7 @@
 import '../scanner/token.dart'
     show isBinaryOperator, isMinusOperator, isUserDefinableOperator;
 
-import '../scope.dart' show ProblemBuilder;
+import '../scope.dart';
 
 import '../severity.dart' show Severity;
 
@@ -789,7 +815,7 @@
     if (formals?.parameters != null) {
       for (int i = 0; i < formals.parameters.length; i++) {
         FormalParameterBuilder parameter = formals.parameters[i];
-        Expression initializer = parameter.target.initializer;
+        Expression initializer = parameter.variable.initializer;
         if (parameter.isOptional || initializer != null) {
           if (parameter.isOptional) {
             initializer ??= forest.createNullLiteral(
@@ -847,7 +873,7 @@
           // Add them as local variable to put them in scope of the body.
           List<Statement> statements = <Statement>[];
           for (FormalParameterBuilder parameter in builder.formals) {
-            statements.add(parameter.target);
+            statements.add(parameter.variable);
           }
           statements.add(body);
           body = forest.createBlock(charOffset, statements);
@@ -1044,15 +1070,11 @@
           // that it is unresolved.
           assert(redirectingFactoryBody.isUnresolved);
           String errorName = redirectingFactoryBody.unresolvedName;
-
-          replacementNode = throwNoSuchMethodError(
-              forest.createNullLiteral(invocation.fileOffset),
-              errorName,
-              forest.createArguments(
-                  noLocation, invocation.arguments.positional,
-                  types: invocation.arguments.types,
-                  named: invocation.arguments.named),
-              initialTarget.fileOffset);
+          replacementNode = buildProblem(
+              fasta.templateMethodNotFound.withArguments(errorName),
+              invocation.fileOffset,
+              noLength,
+              suppressMessage: true);
         } else {
           Substitution substitution = Substitution.fromPairs(
               initialTarget.function.typeParameters,
@@ -1511,13 +1533,16 @@
             token.charOffset, token.length);
       }
     } else {
-      Expression result = buildMethodInvocation(a, new Name(operator),
-          forest.createArguments(noLocation, <Expression>[b]), token.charOffset,
+      Expression result = buildMethodInvocation(
+          a,
+          new Name(operator),
+          forest.createArguments(token.charOffset, <Expression>[b]),
+          token.charOffset,
           // This *could* be a constant expression, we can't know without
           // evaluating [a] and [b].
           isConstantExpression: !isSuper,
           isSuper: isSuper);
-      return negate ? forest.createNot(noLocation, result) : result;
+      return negate ? forest.createNot(token.charOffset, result) : result;
     }
   }
 
@@ -1594,7 +1619,17 @@
         contextMessage = fasta.templateCandidateFoundIsDefaultConstructor
             .withArguments(candidate.enclosingClass.name);
       } else {
-        length = name.length;
+        if (candidate is Constructor) {
+          if (candidate.name.name == '') {
+            length = candidate.enclosingClass.name.length;
+          } else {
+            // Assume no spaces around the dot. Not perfect, but probably the
+            // best we can do with the information available.
+            length = candidate.enclosingClass.name.length + 1 + name.length;
+          }
+        } else {
+          length = name.length;
+        }
         contextMessage = fasta.messageCandidateFound;
       }
       context = [contextMessage.withLocation(uri, offset, length)];
@@ -1875,14 +1910,24 @@
       Builder setter =
           _getCorrespondingSetterBuilder(scope, declaration, name, charOffset);
       // TODO(johnniwinther): Check for constantContext like below?
+      if (declaration.isField) {
+        declaration = null;
+      }
+      if (setter != null && (setter.isField || setter.isStatic)) {
+        setter = null;
+      }
+      if (declaration == null && setter == null) {
+        return new UnresolvedNameGenerator(
+            this, token, new Name(name, libraryBuilder.nameOrigin));
+      }
       return new ExtensionInstanceAccessGenerator.fromBuilder(
           this,
+          token,
           extensionBuilder.extension,
           name,
           extensionThis,
           extensionTypeParameters,
           declaration,
-          token,
           setter);
     } else if (declaration.isRegularMethod) {
       assert(declaration.isStatic || declaration.isTopLevel);
@@ -2810,7 +2855,7 @@
         push(new UnresolvedType(
             new NamedTypeBuilder(name,
                 libraryBuilder.nullableBuilderIfTrue(isMarkedAsNullable), null)
-              ..bind(new InvalidTypeBuilder(
+              ..bind(new InvalidTypeDeclarationBuilder(
                   name,
                   message.withLocation(
                       uri, offset, lengthOfSpan(beginToken, suffix)))),
@@ -2832,7 +2877,7 @@
           name.message, name.charOffset, name.name.length, name.fileUri);
       result = new NamedTypeBuilder(name.name,
           libraryBuilder.nullableBuilderIfTrue(isMarkedAsNullable), null)
-        ..bind(new InvalidTypeBuilder(
+        ..bind(new InvalidTypeDeclarationBuilder(
             name.name,
             name.message.withLocation(
                 name.fileUri, name.charOffset, name.name.length)));
@@ -3231,8 +3276,8 @@
     push(forest.createCatch(
         offsetForToken(onKeyword ?? catchKeyword),
         exceptionType,
-        exception?.target,
-        stackTrace?.target,
+        exception?.variable,
+        stackTrace?.variable,
         coreTypes.stackTraceRawType(libraryBuilder.nonNullable),
         body));
     if (compileTimeErrors == null) {
@@ -3518,12 +3563,8 @@
         return node;
       } else {
         assert(constness == Constness.implicit);
-        StaticInvocation node =
-            new StaticInvocation(target, arguments, isConst: false)
-              ..fileOffset = charOffset;
-        libraryBuilder.checkBoundsInStaticInvocation(
-            node, typeEnvironment, uri);
-        return node;
+        return new StaticInvocation(target, arguments, isConst: false)
+          ..fileOffset = charOffset;
       }
     }
   }
@@ -3767,12 +3808,12 @@
         return buildProblem(fasta.messageEnumInstantiation,
             nameToken.charOffset, nameToken.length);
       }
-      Builder b =
+      MemberBuilder b =
           type.findConstructorOrFactory(name, charOffset, uri, libraryBuilder);
-      Member target = b?.target;
+      Member target = b?.member;
       if (b == null) {
         // Not found. Reported below.
-      } else if (b is ProblemBuilder) {
+      } else if (b is AmbiguousMemberBuilder) {
         message = b.message.withLocation(uri, charOffset, noLength);
       } else if (b.isConstructor) {
         if (type.isAbstract) {
@@ -3803,7 +3844,7 @@
       } else {
         errorName ??= debugName(type.name, name);
       }
-    } else if (type is InvalidTypeBuilder) {
+    } else if (type is InvalidTypeDeclarationBuilder) {
       LocatedMessage message = type.message;
       return evaluateArgumentsBefore(
           arguments,
@@ -4827,6 +4868,9 @@
     TypeVariableBuilder variable = typeVariables[index];
     variable.bound = bound?.builder;
     if (variance != null) {
+      if (!libraryBuilder.loader.target.enableVariance) {
+        reportVarianceModifierNotEnabled(variance);
+      }
       variable.variance = Variance.fromString(variance.lexeme);
     }
   }
@@ -4857,13 +4901,6 @@
   }
 
   @override
-  void handleVarianceModifier(Token variance) {
-    if (!libraryBuilder.loader.target.enableVariance) {
-      reportVarianceModifierNotEnabled(variance);
-    }
-  }
-
-  @override
   void handleNoTypeVariables(Token token) {
     debugEvent("NoTypeVariables");
     enterFunctionTypeScope(null);
@@ -4909,7 +4946,7 @@
       {List<LocatedMessage> context}) {
     int charOffset = expression.fileOffset;
     Severity severity = message.code.severity;
-    if (severity == Severity.error || severity == Severity.errorLegacyWarning) {
+    if (severity == Severity.error) {
       return wrapInLocatedProblem(
           expression, message.withLocation(uri, charOffset, length),
           context: context);
@@ -4966,10 +5003,10 @@
       [int charOffset = -1]) {
     addProblemErrorIfConst(message, charOffset, className.length);
     // TODO(ahe): The following doesn't make sense to Analyzer AST.
-    Builder constructor =
+    MemberBuilder constructor =
         libraryBuilder.loader.getAbstractClassInstantiationError();
     Expression invocation = buildStaticInvocation(
-        constructor.target,
+        constructor.member,
         forest.createArguments(charOffset,
             <Expression>[forest.createStringLiteral(charOffset, className)]),
         constness: Constness.explicitNew,
@@ -4999,15 +5036,6 @@
       ..fileOffset = charOffset;
   }
 
-  Initializer buildInvalidSuperInitializer(
-      Constructor target, ArgumentsImpl arguments, Expression expression,
-      [int charOffset = -1]) {
-    needsImplicitSuperInitializer = false;
-    return new InvalidSuperInitializerJudgment(
-        target, arguments, new VariableDeclaration.forValue(expression))
-      ..fileOffset = charOffset;
-  }
-
   Initializer buildDuplicatedInitializer(Field field, Expression value,
       String name, int offset, int previousInitializerOffset) {
     return new ShadowInvalidFieldInitializer(
@@ -5060,10 +5088,10 @@
                   .withArguments(name)
                   .withLocation(uri, builder.charOffset, name.length)
             ]);
-        Builder constructor =
+        MemberBuilder constructor =
             libraryBuilder.loader.getDuplicatedFieldInitializerError();
         Expression invocation = buildStaticInvocation(
-            constructor.target,
+            constructor.member,
             forest.createArguments(assignmentOffset, <Expression>[
               forest.createStringLiteral(assignmentOffset, name)
             ]),
@@ -5109,12 +5137,8 @@
       bool isSynthetic, Constructor constructor, Arguments arguments,
       [int charOffset = -1]) {
     if (member.isConst && !constructor.isConst) {
-      return buildInvalidSuperInitializer(
-          constructor,
-          arguments,
-          buildProblem(fasta.messageConstConstructorWithNonConstSuper,
-              charOffset, constructor.name.name.length),
-          charOffset);
+      addProblem(fasta.messageConstConstructorWithNonConstSuper, charOffset,
+          constructor.name.name.length);
     }
     needsImplicitSuperInitializer = false;
     return new SuperInitializer(constructor, arguments)
@@ -5189,7 +5213,8 @@
       return new UnresolvedType(
           new NamedTypeBuilder(
               typeParameter.name, builder.nullabilityBuilder, null)
-            ..bind(new InvalidTypeBuilder(typeParameter.name, message)),
+            ..bind(
+                new InvalidTypeDeclarationBuilder(typeParameter.name, message)),
           unresolved.charOffset,
           unresolved.fileUri);
     }
@@ -5572,9 +5597,9 @@
     if (parameters != null) {
       for (FormalParameterBuilder parameter in parameters) {
         if (parameter.isNamed) {
-          namedParameters.add(parameter.target);
+          namedParameters.add(parameter.variable);
         } else {
-          positionalParameters.add(parameter.target);
+          positionalParameters.add(parameter.variable);
         }
       }
       namedParameters.sort((VariableDeclaration a, VariableDeclaration b) {
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 dd83926..5820b4f 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
@@ -28,6 +28,19 @@
 import 'package:kernel/type_algebra.dart' show Substitution;
 import 'package:kernel/type_environment.dart';
 
+import '../builder/builder.dart';
+import '../builder/class_builder.dart';
+import '../builder/field_builder.dart';
+import '../builder/formal_parameter_builder.dart';
+import '../builder/library_builder.dart';
+import '../builder/member_builder.dart';
+import '../builder/named_type_builder.dart';
+import '../builder/nullability_builder.dart';
+import '../builder/procedure_builder.dart';
+import '../builder/type_builder.dart';
+import '../builder/type_declaration_builder.dart';
+import '../builder/type_variable_builder.dart';
+
 import '../dill/dill_member_builder.dart' show DillMemberBuilder;
 
 import '../loader.dart' show Loader;
@@ -75,20 +88,7 @@
 
 import 'forwarding_node.dart' show ForwardingNode;
 
-import 'kernel_builder.dart'
-    show
-        Builder,
-        FormalParameterBuilder,
-        ImplicitFieldType,
-        ClassBuilder,
-        FieldBuilder,
-        NamedTypeBuilder,
-        ProcedureBuilder,
-        LibraryBuilder,
-        MemberBuilder,
-        NullabilityBuilder,
-        TypeBuilder,
-        TypeVariableBuilder;
+import 'kernel_builder.dart' show ImplicitFieldType;
 
 import 'types.dart' show Types;
 
@@ -1186,7 +1186,7 @@
 
     Scope scope = classBuilder.scope;
     if (classBuilder.isMixinApplication) {
-      Builder mixin = classBuilder.mixedInType.declaration;
+      TypeDeclarationBuilder mixin = classBuilder.mixedInType.declaration;
       inferMixinApplication();
       // recordSupertype(cls.mixedInType);
       while (mixin.isNamedMixinApplication) {
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 f477cee..4b10818 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -72,6 +72,7 @@
     {bool keepFields: true,
     bool evaluateAnnotations: true,
     bool desugarSets: false,
+    bool enableTripleShift: false,
     bool errorOnUnevaluatedConstant: false,
     CoreTypes coreTypes,
     ClassHierarchy hierarchy}) {
@@ -85,6 +86,7 @@
       typeEnvironment, errorReporter,
       keepFields: keepFields,
       desugarSets: desugarSets,
+      enableTripleShift: enableTripleShift,
       errorOnUnevaluatedConstant: errorOnUnevaluatedConstant,
       evaluateAnnotations: evaluateAnnotations);
   return component;
@@ -100,6 +102,7 @@
     bool keepVariables: false,
     bool evaluateAnnotations: true,
     bool desugarSets: false,
+    bool enableTripleShift: false,
     bool errorOnUnevaluatedConstant: false}) {
   final ConstantsTransformer constantsTransformer = new ConstantsTransformer(
       backend,
@@ -108,6 +111,7 @@
       keepVariables,
       evaluateAnnotations,
       desugarSets,
+      enableTripleShift,
       errorOnUnevaluatedConstant,
       typeEnvironment,
       errorReporter);
@@ -126,6 +130,7 @@
   final bool keepVariables;
   final bool evaluateAnnotations;
   final bool desugarSets;
+  final bool enableTripleShift;
   final bool errorOnUnevaluatedConstant;
 
   ConstantsTransformer(
@@ -135,12 +140,14 @@
       this.keepVariables,
       this.evaluateAnnotations,
       this.desugarSets,
+      this.enableTripleShift,
       this.errorOnUnevaluatedConstant,
       this.typeEnvironment,
       ErrorReporter errorReporter)
       : constantEvaluator = new ConstantEvaluator(
             backend, environmentDefines, typeEnvironment, errorReporter,
             desugarSets: desugarSets,
+            enableTripleShift: enableTripleShift,
             errorOnUnevaluatedConstant: errorOnUnevaluatedConstant);
 
   // Transform the library/class members:
@@ -493,6 +500,8 @@
   final bool desugarSets;
   final Field unmodifiableSetMap;
 
+  final bool enableTripleShift;
+
   final bool Function(DartType) isInstantiated =
       new IsInstantiatedVisitor().isInstantiated;
 
@@ -522,7 +531,9 @@
 
   ConstantEvaluator(this.backend, this.environmentDefines, this.typeEnvironment,
       this.errorReporter,
-      {this.desugarSets = false, this.errorOnUnevaluatedConstant = false})
+      {this.desugarSets = false,
+      this.enableTripleShift = false,
+      this.errorOnUnevaluatedConstant = false})
       : numberSemantics = backend.numberSemantics,
         coreTypes = typeEnvironment.coreTypes,
         canonicalizationCache = <Constant, Constant>{},
@@ -893,18 +904,9 @@
   @override
   Constant visitConstructorInvocation(ConstructorInvocation node) {
     final Constructor constructor = node.target;
+    checkConstructorConst(node, constructor);
+
     final Class klass = constructor.enclosingClass;
-    bool isSymbol = klass == coreTypes.internalSymbolClass;
-    if (!constructor.isConst) {
-      return reportInvalid(node, 'Non-const constructor invocation.');
-    }
-    if (constructor.function.body != null &&
-        constructor.function.body is! EmptyStatement) {
-      return reportInvalid(
-          node,
-          'Constructor "$node" has non-trivial body '
-          '"${constructor.function.body.runtimeType}".');
-    }
     if (klass.isAbstract) {
       return reportInvalid(
           node, 'Constructor "$node" belongs to abstract class "${klass}".');
@@ -914,6 +916,7 @@
         evaluatePositionalArguments(node.arguments);
     final Map<String, Constant> named = evaluateNamedArguments(node.arguments);
 
+    bool isSymbol = klass == coreTypes.internalSymbolClass;
     if (isSymbol && shouldBeUnevaluated) {
       return unevaluated(
           node,
@@ -964,6 +967,19 @@
     });
   }
 
+  void checkConstructorConst(TreeNode node, Constructor constructor) {
+    if (!constructor.isConst) {
+      reportInvalid(node, 'Non-const constructor invocation.');
+    }
+    if (constructor.function.body != null &&
+        constructor.function.body is! EmptyStatement) {
+      reportInvalid(
+          node,
+          'Constructor "$node" has non-trivial body '
+          '"${constructor.function.body.runtimeType}".');
+    }
+  }
+
   @override
   Constant visitInstanceCreation(InstanceCreation node) {
     return withNewInstanceBuilder(node.classNode, node.typeArguments, () {
@@ -1016,6 +1032,7 @@
       '~',
       '<<',
       '>>',
+      '>>>',
       '<',
       '<=',
       '>',
@@ -1038,7 +1055,7 @@
 
     String last = parts.last;
     if (operatorNames.contains(last)) {
-      return true;
+      return enableTripleShift || last != '>>>';
     }
     if (last.endsWith('=')) {
       last = last.substring(0, last.length - 1);
@@ -1159,6 +1176,7 @@
             env.addVariableValue(
                 variable, _evaluateSubexpression(variable.initializer));
           } else if (init is SuperInitializer) {
+            checkConstructorConst(init, constructor);
             handleConstructorInvocation(
                 init.target,
                 evaluateSuperTypeArguments(
@@ -1168,6 +1186,7 @@
           } else if (init is RedirectingInitializer) {
             // Since a redirecting constructor targets a constructor of the same
             // class, we pass the same [typeArguments].
+            checkConstructorConst(init, constructor);
             handleConstructorInvocation(
                 init.target,
                 typeArguments,
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 1251c2e..05fc8ed 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
@@ -11,13 +11,19 @@
 
 import '../../scanner/token.dart' show Token;
 
-import '../constant_context.dart' show ConstantContext;
-
-import '../builder/builder.dart'
-    show NullabilityBuilder, PrefixBuilder, TypeDeclarationBuilder;
+import '../builder/builder.dart';
 import '../builder/declaration_builder.dart';
 import '../builder/extension_builder.dart';
+import '../builder/invalid_type_declaration_builder.dart';
 import '../builder/member_builder.dart';
+import '../builder/named_type_builder.dart';
+import '../builder/nullability_builder.dart';
+import '../builder/prefix_builder.dart';
+import '../builder/type_builder.dart';
+import '../builder/type_declaration_builder.dart';
+import '../builder/unresolved_type.dart';
+
+import '../constant_context.dart' show ConstantContext;
 
 import '../fasta_codes.dart';
 
@@ -69,16 +75,7 @@
         Procedure,
         VariableDeclaration;
 
-import 'kernel_builder.dart'
-    show
-        AccessErrorBuilder,
-        Builder,
-        InvalidTypeBuilder,
-        LoadLibraryBuilder,
-        NamedTypeBuilder,
-        TypeBuilder,
-        UnlinkedDeclaration,
-        UnresolvedType;
+import 'kernel_builder.dart' show LoadLibraryBuilder, UnlinkedDeclaration;
 
 import 'kernel_shadow_ast.dart';
 
@@ -257,7 +254,7 @@
     Message message = templateNotAType.withArguments(token.lexeme);
     _helper.libraryBuilder
         .addProblem(message, fileOffset, lengthForToken(token), _uri);
-    result.bind(result.buildInvalidType(
+    result.bind(result.buildInvalidTypeDeclarationBuilder(
         message.withLocation(_uri, fileOffset, lengthForToken(token))));
     return result;
   }
@@ -1654,38 +1651,55 @@
 
   factory ExtensionInstanceAccessGenerator.fromBuilder(
       ExpressionGeneratorHelper helper,
+      Token token,
       Extension extension,
       String targetName,
       VariableDeclaration extensionThis,
       List<TypeParameter> extensionTypeParameters,
-      Builder declaration,
-      Token token,
-      Builder builderSetter) {
-    if (declaration is AccessErrorBuilder) {
-      AccessErrorBuilder error = declaration;
-      declaration = error.builder;
-      // We should only see an access error here if we've looked up a setter
-      // when not explicitly looking for a setter.
-      assert(declaration.isSetter);
-    } else if (declaration.target == null) {
-      return unhandled(
-          "${declaration.runtimeType}",
-          "InstanceExtensionAccessGenerator.fromBuilder",
-          offsetForToken(token),
-          helper.uri);
-    }
+      Builder getterBuilder,
+      Builder setterBuilder) {
     Procedure readTarget;
     Procedure invokeTarget;
-    if (declaration.isGetter) {
-      readTarget = declaration.target;
-    } else if (declaration.isRegularMethod) {
-      MemberBuilder procedureBuilder = declaration;
-      readTarget = procedureBuilder.extensionTearOff;
-      invokeTarget = procedureBuilder.procedure;
+    if (getterBuilder != null) {
+      if (getterBuilder is AccessErrorBuilder) {
+        AccessErrorBuilder error = getterBuilder;
+        getterBuilder = error.builder;
+        // We should only see an access error here if we've looked up a setter
+        // when not explicitly looking for a setter.
+        assert(getterBuilder.isSetter);
+      } else if (getterBuilder.target == null) {
+        return unhandled(
+            "${getterBuilder.runtimeType}",
+            "ExtensionInstanceAccessGenerator.fromBuilder",
+            offsetForToken(token),
+            helper.uri);
+      }
+      if (getterBuilder.isGetter) {
+        assert(!getterBuilder.isStatic);
+        readTarget = getterBuilder.target;
+      } else if (getterBuilder.isRegularMethod) {
+        assert(!getterBuilder.isStatic);
+        MemberBuilder procedureBuilder = getterBuilder;
+        readTarget = procedureBuilder.extensionTearOff;
+        invokeTarget = procedureBuilder.procedure;
+      }
     }
     Procedure writeTarget;
-    if (builderSetter != null && builderSetter.isSetter) {
-      writeTarget = builderSetter.target;
+    if (setterBuilder != null) {
+      if (setterBuilder is AccessErrorBuilder) {
+        targetName ??= setterBuilder.name;
+      } else if (setterBuilder.isSetter) {
+        assert(!setterBuilder.isStatic);
+        MemberBuilder memberBuilder = setterBuilder;
+        writeTarget = memberBuilder.member;
+        targetName ??= memberBuilder.name;
+      } else {
+        return unhandled(
+            "${setterBuilder.runtimeType}",
+            "ExtensionInstanceAccessGenerator.fromBuilder",
+            offsetForToken(token),
+            helper.uri);
+      }
     }
     return new ExtensionInstanceAccessGenerator(
         helper,
@@ -1882,6 +1896,10 @@
 ///   }
 ///
 class ExplicitExtensionInstanceAccessGenerator extends Generator {
+  /// The file offset used for the explicit extension application type
+  /// arguments.
+  final int extensionTypeArgumentOffset;
+
   final Extension extension;
 
   /// The name of the original target;
@@ -1927,6 +1945,7 @@
   ExplicitExtensionInstanceAccessGenerator(
       ExpressionGeneratorHelper helper,
       Token token,
+      this.extensionTypeArgumentOffset,
       this.extension,
       this.targetName,
       this.readTarget,
@@ -1945,6 +1964,7 @@
   factory ExplicitExtensionInstanceAccessGenerator.fromBuilder(
       ExpressionGeneratorHelper helper,
       Token token,
+      int extensionTypeArgumentOffset,
       Extension extension,
       Builder getterBuilder,
       Builder setterBuilder,
@@ -1965,10 +1985,12 @@
         // when not explicitly looking for a setter.
         assert(getterBuilder.isSetter);
       } else if (getterBuilder.isGetter) {
+        assert(!getterBuilder.isStatic);
         MemberBuilder memberBuilder = getterBuilder;
         readTarget = memberBuilder.member;
         targetName = memberBuilder.name;
       } else if (getterBuilder.isRegularMethod) {
+        assert(!getterBuilder.isStatic);
         MemberBuilder procedureBuilder = getterBuilder;
         readTarget = procedureBuilder.extensionTearOff;
         invokeTarget = procedureBuilder.procedure;
@@ -1987,6 +2009,7 @@
       if (setterBuilder is AccessErrorBuilder) {
         targetName ??= setterBuilder.name;
       } else if (setterBuilder.isSetter) {
+        assert(!setterBuilder.isStatic);
         MemberBuilder memberBuilder = setterBuilder;
         writeTarget = memberBuilder.member;
         targetName ??= memberBuilder.name;
@@ -2001,6 +2024,7 @@
     return new ExplicitExtensionInstanceAccessGenerator(
         helper,
         token,
+        extensionTypeArgumentOffset,
         extension,
         targetName,
         readTarget,
@@ -2052,7 +2076,8 @@
           readTarget,
           _helper.forest.createArgumentsForExtensionMethod(
               fileOffset, extensionTypeParameterCount, 0, receiver,
-              extensionTypeArguments: _createExtensionTypeArguments()),
+              extensionTypeArguments: _createExtensionTypeArguments(),
+              extensionTypeArgumentOffset: extensionTypeArgumentOffset),
           isTearOff: isReadTearOff);
     }
     return read;
@@ -2230,6 +2255,7 @@
                   extensionTypeParameterCount,
               receiverExpression,
               extensionTypeArguments: _createExtensionTypeArguments(),
+              extensionTypeArgumentOffset: extensionTypeArgumentOffset,
               typeArguments: arguments.types,
               positionalArguments: arguments.positional,
               namedArguments: arguments.named),
@@ -2270,6 +2296,10 @@
 }
 
 class ExplicitExtensionIndexedAccessGenerator extends Generator {
+  /// The file offset used for the explicit extension application type
+  /// arguments.
+  final int extensionTypeArgumentOffset;
+
   final Extension extension;
 
   /// The static [Member] generated for the [] operation.
@@ -2299,6 +2329,7 @@
   ExplicitExtensionIndexedAccessGenerator(
       ExpressionGeneratorHelper helper,
       Token token,
+      this.extensionTypeArgumentOffset,
       this.extension,
       this.readTarget,
       this.writeTarget,
@@ -2313,6 +2344,7 @@
   factory ExplicitExtensionIndexedAccessGenerator.fromBuilder(
       ExpressionGeneratorHelper helper,
       Token token,
+      int extensionTypeArgumentOffset,
       Extension extension,
       Builder getterBuilder,
       Builder setterBuilder,
@@ -2347,6 +2379,7 @@
     return new ExplicitExtensionIndexedAccessGenerator(
         helper,
         token,
+        extensionTypeArgumentOffset,
         extension,
         readTarget,
         writeTarget,
@@ -2375,6 +2408,7 @@
         _forest.createArgumentsForExtensionMethod(
             fileOffset, extensionTypeParameterCount, 0, receiver,
             extensionTypeArguments: _createExtensionTypeArguments(),
+            extensionTypeArgumentOffset: extensionTypeArgumentOffset,
             positionalArguments: <Expression>[index]),
         isTearOff: false);
   }
@@ -2391,6 +2425,7 @@
           _forest.createArgumentsForExtensionMethod(
               fileOffset, extensionTypeParameterCount, 0, receiver,
               extensionTypeArguments: _createExtensionTypeArguments(),
+              extensionTypeArgumentOffset: extensionTypeArgumentOffset,
               positionalArguments: <Expression>[index, value]),
           isTearOff: false);
     } else {
@@ -2543,12 +2578,12 @@
   }
 
   Generator _createInstanceAccess(Token token, Name name, {bool isNullAware}) {
-    Builder getter = extensionBuilder.lookupLocalMember(name.name);
-    if (getter != null && getter.isStatic) {
+    Builder getter = extensionBuilder.lookupLocalMemberByName(name);
+    if (getter != null && (getter.isStatic || getter.isField)) {
       getter = null;
     }
     Builder setter =
-        extensionBuilder.lookupLocalMember(name.name, setter: true);
+        extensionBuilder.lookupLocalMemberByName(name, setter: true);
     if (setter != null && setter.isStatic) {
       setter = null;
     }
@@ -2558,6 +2593,10 @@
     return new ExplicitExtensionInstanceAccessGenerator.fromBuilder(
         _helper,
         token,
+        // TODO(johnniwinther): Improve this. This is the name of the extension
+        // and not the type arguments (or arguments if type arguments are
+        // omitted).
+        fileOffset,
         extensionBuilder.extension,
         getter,
         setter,
@@ -2603,8 +2642,8 @@
 
   @override
   Generator buildIndexedAccess(Expression index, Token token) {
-    Builder getter = extensionBuilder.lookupLocalMember(indexGetName.name);
-    Builder setter = extensionBuilder.lookupLocalMember(indexSetName.name);
+    Builder getter = extensionBuilder.lookupLocalMemberByName(indexGetName);
+    Builder setter = extensionBuilder.lookupLocalMemberByName(indexSetName);
     if (getter == null && setter == null) {
       return new UnresolvedNameGenerator(_helper, token, indexGetName);
     }
@@ -2612,6 +2651,10 @@
     return new ExplicitExtensionIndexedAccessGenerator.fromBuilder(
         _helper,
         token,
+        // TODO(johnniwinther): Improve this. This is the name of the extension
+        // and not the type arguments (or arguments if type arguments are
+        // omitted).
+        fileOffset,
         extensionBuilder.extension,
         getter,
         setter,
@@ -2814,8 +2857,9 @@
     TypeBuilder type = suffixGenerator.buildTypeWithResolvedArguments(
         nullabilityBuilder, arguments);
     LocatedMessage message;
-    if (type is NamedTypeBuilder && type.declaration is InvalidTypeBuilder) {
-      InvalidTypeBuilder declaration = type.declaration;
+    if (type is NamedTypeBuilder &&
+        type.declaration is InvalidTypeDeclarationBuilder) {
+      InvalidTypeDeclarationBuilder declaration = type.declaration;
       message = declaration.message;
     } else {
       int charOffset = offsetForToken(prefixGenerator.token);
@@ -2830,7 +2874,7 @@
         new NamedTypeBuilder(name, nullabilityBuilder, null);
     _helper.libraryBuilder.addProblem(
         message.messageObject, message.charOffset, message.length, message.uri);
-    result.bind(result.buildInvalidType(message));
+    result.bind(result.buildInvalidTypeDeclarationBuilder(message));
     return result;
   }
 
@@ -2973,8 +3017,8 @@
   @override
   Expression get expression {
     if (super.expression == null) {
-      if (declaration is InvalidTypeBuilder) {
-        InvalidTypeBuilder declaration = this.declaration;
+      if (declaration is InvalidTypeDeclarationBuilder) {
+        InvalidTypeDeclarationBuilder declaration = this.declaration;
         super.expression = _helper.buildProblemErrorIfConst(
             declaration.message.messageObject, fileOffset, token.length);
       } else {
@@ -3910,7 +3954,7 @@
         offsetForToken(prefixGenerator.token),
         lengthOfSpan(prefixGenerator.token, token),
         _uri);
-    result.bind(result.buildInvalidType(message.withLocation(
+    result.bind(result.buildInvalidTypeDeclarationBuilder(message.withLocation(
         _uri,
         offsetForToken(prefixGenerator.token),
         lengthOfSpan(prefixGenerator.token, token))));
@@ -4007,8 +4051,8 @@
     NamedTypeBuilder result =
         new NamedTypeBuilder(token.lexeme, nullabilityBuilder, null);
     _helper.libraryBuilder.addProblem(message, fileOffset, noLength, _uri);
-    result.bind(result
-        .buildInvalidType(message.withLocation(_uri, fileOffset, noLength)));
+    result.bind(result.buildInvalidTypeDeclarationBuilder(
+        message.withLocation(_uri, fileOffset, noLength)));
     return result;
   }
 
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 a6d6421..b327ff7 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
@@ -6,6 +6,12 @@
 
 import '../../scanner/token.dart' show Token;
 
+import '../builder/builder.dart';
+import '../builder/library_builder.dart';
+import '../builder/prefix_builder.dart';
+import '../builder/type_declaration_builder.dart';
+import '../builder/unresolved_type.dart';
+
 import '../constant_context.dart' show ConstantContext;
 
 import '../fasta_codes.dart' show LocatedMessage;
@@ -22,7 +28,7 @@
 
 import 'forest.dart' show Forest;
 
-import 'kernel_builder.dart' show Builder, PrefixBuilder, UnresolvedType;
+import '../scope.dart';
 
 import 'kernel_ast_api.dart'
     show
@@ -39,9 +45,6 @@
         TypeParameter,
         VariableDeclaration;
 
-import 'kernel_builder.dart'
-    show PrefixBuilder, LibraryBuilder, TypeDeclarationBuilder;
-
 abstract class ExpressionGeneratorHelper implements InferenceHelper {
   LibraryBuilder get libraryBuilder;
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/forest.dart b/pkg/front_end/lib/src/fasta/kernel/forest.dart
index dc4369b..c551700 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forest.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forest.dart
@@ -40,6 +40,7 @@
       int typeParameterCount,
       Expression receiver,
       {List<DartType> extensionTypeArguments = const <DartType>[],
+      int extensionTypeArgumentOffset,
       List<DartType> typeArguments = const <DartType>[],
       List<Expression> positionalArguments = const <Expression>[],
       List<NamedExpression> namedArguments = const <NamedExpression>[]}) {
@@ -47,6 +48,7 @@
     return new ArgumentsImpl.forExtensionMethod(
         extensionTypeParameterCount, typeParameterCount, receiver,
         extensionTypeArguments: extensionTypeArguments,
+        extensionTypeArgumentOffset: extensionTypeArgumentOffset,
         typeArguments: typeArguments,
         positionalArguments: positionalArguments,
         namedArguments: namedArguments)
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 99e4ad8..d1eb056 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,33 +9,37 @@
 
 import '../../scanner/token.dart' show Token;
 
+import '../builder/member_builder.dart';
+
 import '../problems.dart' show unsupported;
 
-import 'kernel_builder.dart' show MemberBuilder;
-
 class ImplicitFieldType extends DartType {
-  final MemberBuilder member;
+  final MemberBuilder memberBuilder;
   Token initializerToken;
   bool isStarted = false;
 
-  ImplicitFieldType(this.member, this.initializerToken);
+  ImplicitFieldType(this.memberBuilder, this.initializerToken);
 
-  Nullability get nullability =>
-      unsupported("nullability", member.charOffset, member.fileUri);
+  Nullability get nullability => unsupported(
+      "nullability", memberBuilder.charOffset, memberBuilder.fileUri);
 
   R accept<R>(DartTypeVisitor<R> v) {
-    throw unsupported("accept", member.charOffset, member.fileUri);
+    throw unsupported(
+        "accept", memberBuilder.charOffset, memberBuilder.fileUri);
   }
 
   R accept1<R, A>(DartTypeVisitor1<R, A> v, arg) {
-    throw unsupported("accept1", member.charOffset, member.fileUri);
+    throw unsupported(
+        "accept1", memberBuilder.charOffset, memberBuilder.fileUri);
   }
 
   visitChildren(Visitor<Object> v) {
-    unsupported("visitChildren", member.charOffset, member.fileUri);
+    unsupported(
+        "visitChildren", memberBuilder.charOffset, memberBuilder.fileUri);
   }
 
   ImplicitFieldType withNullability(Nullability nullability) {
-    return unsupported("withNullability", member.charOffset, member.fileUri);
+    return unsupported(
+        "withNullability", memberBuilder.charOffset, memberBuilder.fileUri);
   }
 }
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 c1b4dc0..57503845 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -391,17 +391,16 @@
     FunctionType calleeType = node.target != null
         ? node.target.function.functionType
         : new FunctionType([], const DynamicType());
-    bool hadExplicitTypeArguments =
-        getExplicitTypeArguments(node.arguments) != null;
+    TypeArgumentsInfo typeArgumentsInfo = getTypeArgumentsInfo(node.arguments);
     DartType inferredType = inferrer.inferInvocation(
         typeContext, node.fileOffset, calleeType, node.arguments);
     Expression replacement = new StaticInvocation(node.target, node.arguments);
-    if (!inferrer.isTopLevel &&
-        !hadExplicitTypeArguments &&
-        node.target != null) {
+    if (!inferrer.isTopLevel && node.target != null) {
       inferrer.library.checkBoundsInStaticInvocation(
-          replacement, inferrer.typeSchemaEnvironment, inferrer.helper.uri,
-          inferred: true);
+          replacement,
+          inferrer.typeSchemaEnvironment,
+          inferrer.helper.uri,
+          typeArgumentsInfo);
     }
     node.replaceWith(replacement);
     inferredType =
@@ -570,8 +569,11 @@
         iterable, elementType, typeNeeded || typeChecksNeeded,
         isAsync: isAsync);
     if (typeNeeded) {
-      inferrer.instrumentation?.record(inferrer.uri, variable.fileOffset,
-          'type', new InstrumentationValueForType(inferredType));
+      inferrer.instrumentation?.record(
+          inferrer.uriForInstrumentation,
+          variable.fileOffset,
+          'type',
+          new InstrumentationValueForType(inferredType));
       variable.type = inferredType;
     }
 
@@ -1205,7 +1207,7 @@
           inferredTypes);
       inferredTypeArgument = inferredTypes[0];
       inferrer.instrumentation?.record(
-          inferrer.uri,
+          inferrer.uriForInstrumentation,
           node.fileOffset,
           'typeArgs',
           new InstrumentationValueForTypeArgs([inferredTypeArgument]));
@@ -1740,7 +1742,7 @@
             inferredTypesForSet);
         DartType inferredTypeArgument = inferredTypesForSet[0];
         inferrer.instrumentation?.record(
-            inferrer.uri,
+            inferrer.uriForInstrumentation,
             node.fileOffset,
             'typeArgs',
             new InstrumentationValueForTypeArgs([inferredTypeArgument]));
@@ -1794,7 +1796,7 @@
       inferredKeyType = inferredTypes[0];
       inferredValueType = inferredTypes[1];
       inferrer.instrumentation?.record(
-          inferrer.uri,
+          inferrer.uriForInstrumentation,
           node.fileOffset,
           'typeArgs',
           new InstrumentationValueForTypeArgs(
@@ -2313,7 +2315,10 @@
           noLength);
     } else {
       assert(indexSetTarget.isInstanceMember);
-      inferrer.instrumentation?.record(inferrer.uri, node.fileOffset, 'target',
+      inferrer.instrumentation?.record(
+          inferrer.uriForInstrumentation,
+          node.fileOffset,
+          'target',
           new InstrumentationValueForMember(node.setter));
       assignment = new SuperMethodInvocation(
           indexSetName,
@@ -2509,8 +2514,11 @@
 
       if (checkKind == MethodContravarianceCheckKind.checkMethodReturn) {
         if (inferrer.instrumentation != null) {
-          inferrer.instrumentation.record(inferrer.uri, node.readOffset,
-              'checkReturn', new InstrumentationValueForType(readType));
+          inferrer.instrumentation.record(
+              inferrer.uriForInstrumentation,
+              node.readOffset,
+              'checkReturn',
+              new InstrumentationValueForType(readType));
         }
         read = new AsExpression(read, readType)
           ..isTypeError = true
@@ -2680,7 +2688,10 @@
           '[]'.length);
     } else {
       assert(readTarget.isInstanceMember);
-      inferrer.instrumentation?.record(inferrer.uri, node.readOffset, 'target',
+      inferrer.instrumentation?.record(
+          inferrer.uriForInstrumentation,
+          node.readOffset,
+          'target',
           new InstrumentationValueForMember(node.getter));
       read = new SuperMethodInvocation(
           indexGetName,
@@ -2710,7 +2721,10 @@
           '[]='.length);
     } else {
       assert(writeTarget.isInstanceMember);
-      inferrer.instrumentation?.record(inferrer.uri, node.writeOffset, 'target',
+      inferrer.instrumentation?.record(
+          inferrer.uriForInstrumentation,
+          node.writeOffset,
+          'target',
           new InstrumentationValueForMember(node.setter));
       write = new SuperMethodInvocation(
           indexSetName,
@@ -3001,8 +3015,11 @@
         ..fileOffset = node.readOffset;
       if (readCheckKind == MethodContravarianceCheckKind.checkMethodReturn) {
         if (inferrer.instrumentation != null) {
-          inferrer.instrumentation.record(inferrer.uri, node.readOffset,
-              'checkReturn', new InstrumentationValueForType(readType));
+          inferrer.instrumentation.record(
+              inferrer.uriForInstrumentation,
+              node.readOffset,
+              'checkReturn',
+              new InstrumentationValueForType(readType));
         }
         read = new AsExpression(read, readType)
           ..isTypeError = true
@@ -3073,8 +3090,11 @@
 
       if (binaryCheckKind == MethodContravarianceCheckKind.checkMethodReturn) {
         if (inferrer.instrumentation != null) {
-          inferrer.instrumentation.record(inferrer.uri, node.binaryOffset,
-              'checkReturn', new InstrumentationValueForType(readType));
+          inferrer.instrumentation.record(
+              inferrer.uriForInstrumentation,
+              node.binaryOffset,
+              'checkReturn',
+              new InstrumentationValueForType(readType));
         }
         binary = new AsExpression(binary, binaryType)
           ..isTypeError = true
@@ -3239,8 +3259,11 @@
         ..fileOffset = node.readOffset;
       if (readCheckKind == MethodContravarianceCheckKind.checkMethodReturn) {
         if (inferrer.instrumentation != null) {
-          inferrer.instrumentation.record(inferrer.uri, node.readOffset,
-              'checkReturn', new InstrumentationValueForType(readType));
+          inferrer.instrumentation.record(
+              inferrer.uriForInstrumentation,
+              node.readOffset,
+              'checkReturn',
+              new InstrumentationValueForType(readType));
         }
         read = new AsExpression(read, readType)
           ..isTypeError = true
@@ -3310,8 +3333,11 @@
 
       if (binaryCheckKind == MethodContravarianceCheckKind.checkMethodReturn) {
         if (inferrer.instrumentation != null) {
-          inferrer.instrumentation.record(inferrer.uri, node.binaryOffset,
-              'checkReturn', new InstrumentationValueForType(readType));
+          inferrer.instrumentation.record(
+              inferrer.uriForInstrumentation,
+              node.binaryOffset,
+              'checkReturn',
+              new InstrumentationValueForType(readType));
         }
         binary = new AsExpression(binary, binaryType)
           ..isTypeError = true
@@ -3473,7 +3499,10 @@
           '[]'.length);
     } else {
       assert(readTarget.isInstanceMember);
-      inferrer.instrumentation?.record(inferrer.uri, node.readOffset, 'target',
+      inferrer.instrumentation?.record(
+          inferrer.uriForInstrumentation,
+          node.readOffset,
+          'target',
           new InstrumentationValueForMember(node.getter));
       read = new SuperMethodInvocation(
           indexGetName,
@@ -3547,8 +3576,11 @@
 
       if (binaryCheckKind == MethodContravarianceCheckKind.checkMethodReturn) {
         if (inferrer.instrumentation != null) {
-          inferrer.instrumentation.record(inferrer.uri, node.binaryOffset,
-              'checkReturn', new InstrumentationValueForType(readType));
+          inferrer.instrumentation.record(
+              inferrer.uriForInstrumentation,
+              node.binaryOffset,
+              'checkReturn',
+              new InstrumentationValueForType(readType));
         }
         binary = new AsExpression(binary, binaryType)
           ..isTypeError = true
@@ -3595,7 +3627,10 @@
           '[]='.length);
     } else {
       assert(writeTarget.isInstanceMember);
-      inferrer.instrumentation?.record(inferrer.uri, node.writeOffset, 'target',
+      inferrer.instrumentation?.record(
+          inferrer.uriForInstrumentation,
+          node.writeOffset,
+          'target',
           new InstrumentationValueForMember(node.setter));
       write = new SuperMethodInvocation(
           indexSetName,
@@ -3775,8 +3810,11 @@
 
       if (binaryCheckKind == MethodContravarianceCheckKind.checkMethodReturn) {
         if (inferrer.instrumentation != null) {
-          inferrer.instrumentation.record(inferrer.uri, node.binaryOffset,
-              'checkReturn', new InstrumentationValueForType(readType));
+          inferrer.instrumentation.record(
+              inferrer.uriForInstrumentation,
+              node.binaryOffset,
+              'checkReturn',
+              new InstrumentationValueForType(readType));
         }
         binary = new AsExpression(binary, binaryType)
           ..isTypeError = true
@@ -4017,8 +4055,11 @@
         ..fileOffset = node.readOffset;
       if (readCheckKind == MethodContravarianceCheckKind.checkMethodReturn) {
         if (inferrer.instrumentation != null) {
-          inferrer.instrumentation.record(inferrer.uri, node.readOffset,
-              'checkReturn', new InstrumentationValueForType(readType));
+          inferrer.instrumentation.record(
+              inferrer.uriForInstrumentation,
+              node.readOffset,
+              'checkReturn',
+              new InstrumentationValueForType(readType));
         }
         read = new AsExpression(read, readType)
           ..isTypeError = true
@@ -4244,7 +4285,7 @@
           inferredTypes);
       inferredTypeArgument = inferredTypes[0];
       inferrer.instrumentation?.record(
-          inferrer.uri,
+          inferrer.uriForInstrumentation,
           node.fileOffset,
           'typeArgs',
           new InstrumentationValueForTypeArgs([inferredTypeArgument]));
@@ -4306,16 +4347,15 @@
     FunctionType calleeType = node.target != null
         ? node.target.function.functionType
         : new FunctionType([], const DynamicType());
-    bool hadExplicitTypeArguments =
-        getExplicitTypeArguments(node.arguments) != null;
+    TypeArgumentsInfo typeArgumentsInfo = getTypeArgumentsInfo(node.arguments);
     DartType inferredType = inferrer.inferInvocation(
         typeContext, node.fileOffset, calleeType, node.arguments);
-    if (!inferrer.isTopLevel &&
-        !hadExplicitTypeArguments &&
-        node.target != null) {
+    if (!inferrer.isTopLevel && node.target != null) {
       inferrer.library.checkBoundsInStaticInvocation(
-          node, inferrer.typeSchemaEnvironment, inferrer.helper.uri,
-          inferred: true);
+          node,
+          inferrer.typeSchemaEnvironment,
+          inferrer.helper.uri,
+          typeArgumentsInfo);
     }
     return new ExpressionInferenceResult(inferredType);
   }
@@ -4360,7 +4400,10 @@
   ExpressionInferenceResult visitSuperMethodInvocation(
       SuperMethodInvocation node, DartType typeContext) {
     if (node.interfaceTarget != null) {
-      inferrer.instrumentation?.record(inferrer.uri, node.fileOffset, 'target',
+      inferrer.instrumentation?.record(
+          inferrer.uriForInstrumentation,
+          node.fileOffset,
+          'target',
           new InstrumentationValueForMember(node.interfaceTarget));
     }
     ExpressionInferenceResult result = inferrer.inferSuperMethodInvocation(
@@ -4376,7 +4419,10 @@
   ExpressionInferenceResult visitSuperPropertyGet(
       SuperPropertyGet node, DartType typeContext) {
     if (node.interfaceTarget != null) {
-      inferrer.instrumentation?.record(inferrer.uri, node.fileOffset, 'target',
+      inferrer.instrumentation?.record(
+          inferrer.uriForInstrumentation,
+          node.fileOffset,
+          'target',
           new InstrumentationValueForMember(node.interfaceTarget));
     }
     return inferrer.inferSuperPropertyGet(
@@ -4438,7 +4484,9 @@
               noLength,
               context: [
                 messageSwitchExpressionNotAssignableCause.withLocation(
-                    inferrer.uri, node.expression.fileOffset, noLength)
+                    inferrer.uriForInstrumentation,
+                    node.expression.fileOffset,
+                    noLength)
               ]);
         }
       }
@@ -4525,7 +4573,10 @@
       inferredType = const DynamicType();
     }
     if (node._implicitlyTyped) {
-      inferrer.instrumentation?.record(inferrer.uri, node.fileOffset, 'type',
+      inferrer.instrumentation?.record(
+          inferrer.uriForInstrumentation,
+          node.fileOffset,
+          'type',
           new InstrumentationValueForType(inferredType));
       node.type = inferredType;
     }
@@ -4557,8 +4608,11 @@
     DartType promotedType = inferrer.typePromoter
         .computePromotedType(node._fact, node._scope, mutatedInClosure);
     if (promotedType != null) {
-      inferrer.instrumentation?.record(inferrer.uri, node.fileOffset,
-          'promotedType', new InstrumentationValueForType(promotedType));
+      inferrer.instrumentation?.record(
+          inferrer.uriForInstrumentation,
+          node.fileOffset,
+          'promotedType',
+          new InstrumentationValueForType(promotedType));
     }
     node.promotedType = promotedType;
     DartType type = promotedType ?? declaredOrInferredType;
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_builder.dart
index 7f19f72..21cb163 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_builder.dart
@@ -14,8 +14,6 @@
 
 import '../combinator.dart' as fasta;
 
-export '../builder/builder.dart';
-
 export 'class_hierarchy_builder.dart'
     show ClassHierarchyBuilder, DelayedMember, DelayedOverrideCheck;
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
index e1dbaf4..44da49f 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_shadow_ast.dart
@@ -125,7 +125,7 @@
 
 int getExtensionTypeArgumentCount(Arguments arguments) {
   if (arguments is ArgumentsImpl) {
-    return arguments._extensionTypeArgumentCount;
+    return arguments._explicitExtensionTypeArgumentCount;
   } else {
     // TODO(johnniwinther): Remove this path or assert why it is accepted.
     return 0;
@@ -134,11 +134,11 @@
 
 List<DartType> getExplicitExtensionTypeArguments(Arguments arguments) {
   if (arguments is ArgumentsImpl) {
-    if (arguments._extensionTypeArgumentCount == 0) {
+    if (arguments._explicitExtensionTypeArgumentCount == 0) {
       return null;
     } else {
       return arguments.types
-          .take(arguments._extensionTypeArgumentCount)
+          .take(arguments._explicitExtensionTypeArgumentCount)
           .toList();
     }
   } else {
@@ -147,6 +147,74 @@
   }
 }
 
+/// Information about explicit/implicit type arguments used for error
+/// reporting.
+abstract class TypeArgumentsInfo {
+  const TypeArgumentsInfo();
+
+  /// Returns `true` if the [index]th type argument was inferred.
+  bool isInferred(int index);
+
+  /// Returns the offset to use when reporting an error on the [index]th type
+  /// arguments, using [offset] as the default offset.
+  int getOffsetForIndex(int index, int offset) => offset;
+}
+
+class AllInferredTypeArgumentsInfo extends TypeArgumentsInfo {
+  const AllInferredTypeArgumentsInfo();
+
+  bool isInferred(int index) => true;
+}
+
+class NoneInferredTypeArgumentsInfo extends TypeArgumentsInfo {
+  const NoneInferredTypeArgumentsInfo();
+
+  bool isInferred(int index) => false;
+}
+
+class ExtensionMethodTypeArgumentsInfo implements TypeArgumentsInfo {
+  final ArgumentsImpl arguments;
+
+  ExtensionMethodTypeArgumentsInfo(this.arguments);
+
+  bool isInferred(int index) {
+    if (index < arguments._extensionTypeParameterCount) {
+      // The index refers to a type argument for a type parameter declared on
+      // the extension. Check whether we have enough explicit extension type
+      // arguments.
+      return index >= arguments._explicitExtensionTypeArgumentCount;
+    }
+    // The index refers to a type argument for a type parameter declared on
+    // the method. Check whether we have enough explicit regular type arguments.
+    return index - arguments._extensionTypeParameterCount >=
+        arguments._explicitTypeArgumentCount;
+  }
+
+  int getOffsetForIndex(int index, int offset) {
+    if (index < arguments._extensionTypeParameterCount) {
+      return arguments._extensionTypeArgumentOffset ?? offset;
+    }
+    return offset;
+  }
+}
+
+TypeArgumentsInfo getTypeArgumentsInfo(Arguments arguments) {
+  if (arguments is ArgumentsImpl) {
+    if (arguments._extensionTypeParameterCount == 0) {
+      return arguments._explicitTypeArgumentCount == 0
+          ? const AllInferredTypeArgumentsInfo()
+          : const NoneInferredTypeArgumentsInfo();
+    } else {
+      return new ExtensionMethodTypeArgumentsInfo(arguments);
+    }
+  } else {
+    // This code path should only be taken in situations where there are no
+    // type arguments at all, e.g. calling a user-definable operator.
+    assert(arguments.types.isEmpty);
+    return const NoneInferredTypeArgumentsInfo();
+  }
+}
+
 List<DartType> getExplicitTypeArguments(Arguments arguments) {
   if (arguments is ArgumentsImpl) {
     if (arguments._explicitTypeArgumentCount == 0) {
@@ -245,7 +313,9 @@
   // TODO(johnniwinther): Move this to the static invocation instead.
   final int _extensionTypeParameterCount;
 
-  final int _extensionTypeArgumentCount;
+  final int _explicitExtensionTypeArgumentCount;
+
+  final int _extensionTypeArgumentOffset;
 
   int _explicitTypeArgumentCount;
 
@@ -253,18 +323,22 @@
       {List<DartType> types, List<NamedExpression> named})
       : _explicitTypeArgumentCount = types?.length ?? 0,
         _extensionTypeParameterCount = 0,
-        _extensionTypeArgumentCount = 0,
+        _explicitExtensionTypeArgumentCount = 0,
+        // The offset is unused in this case.
+        _extensionTypeArgumentOffset = null,
         super(positional, types: types, named: named);
 
   ArgumentsImpl.forExtensionMethod(int extensionTypeParameterCount,
       int typeParameterCount, Expression receiver,
       {List<DartType> extensionTypeArguments = const <DartType>[],
+      int extensionTypeArgumentOffset,
       List<DartType> typeArguments = const <DartType>[],
       List<Expression> positionalArguments = const <Expression>[],
       List<NamedExpression> namedArguments = const <NamedExpression>[]})
       : _extensionTypeParameterCount = extensionTypeParameterCount,
-        _extensionTypeArgumentCount = extensionTypeArguments.length,
+        _explicitExtensionTypeArgumentCount = extensionTypeArguments.length,
         _explicitTypeArgumentCount = typeArguments.length,
+        _extensionTypeArgumentOffset = extensionTypeArgumentOffset,
         assert(
             extensionTypeArguments.isEmpty ||
                 extensionTypeArguments.length == extensionTypeParameterCount,
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 6be7601..0bc8ffa 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_target.dart
@@ -45,6 +45,17 @@
 
 import '../../api_prototype/file_system.dart' show FileSystem;
 
+import '../builder/builder.dart';
+import '../builder/class_builder.dart';
+import '../builder/field_builder.dart';
+import '../builder/invalid_type_declaration_builder.dart';
+import '../builder/library_builder.dart';
+import '../builder/named_type_builder.dart';
+import '../builder/nullability_builder.dart';
+import '../builder/procedure_builder.dart';
+import '../builder/type_builder.dart';
+import '../builder/type_declaration_builder.dart';
+
 import '../compiler_context.dart' show CompilerContext;
 
 import '../crash.dart' show withCrashReporting;
@@ -86,19 +97,6 @@
 
 import 'constant_evaluator.dart' as constants show transformLibraries;
 
-import 'kernel_builder.dart'
-    show
-        ClassBuilder,
-        Builder,
-        InvalidTypeBuilder,
-        FieldBuilder,
-        NamedTypeBuilder,
-        ProcedureBuilder,
-        LibraryBuilder,
-        NullabilityBuilder,
-        TypeBuilder,
-        TypeDeclarationBuilder;
-
 import 'kernel_constants.dart' show KernelConstantErrorReporter;
 
 import 'metadata_collector.dart' show MetadataCollector;
@@ -256,10 +254,7 @@
           loader.coreLibrary.lookupLocalMember("dynamic", required: true));
       loader.resolveParts();
       loader.computeLibraryScopes();
-      objectType
-          .bind(loader.coreLibrary.lookupLocalMember("Object", required: true));
-      bottomType
-          .bind(loader.coreLibrary.lookupLocalMember("Null", required: true));
+      setupTopAndBottomTypes();
       loader.resolveTypes();
       loader.computeDefaultTypes(dynamicType, bottomType, objectClassBuilder);
       List<SourceClassBuilder> myClasses =
@@ -465,7 +460,7 @@
       unhandled("${type.runtimeType}", "installForwardingConstructors",
           builder.charOffset, builder.fileUri);
     }
-    if (supertype.isMixinApplication && supertype is SourceClassBuilder) {
+    if (supertype is SourceClassBuilder && supertype.isMixinApplication) {
       installForwardingConstructors(supertype);
     }
     if (supertype is ClassBuilder) {
@@ -479,7 +474,7 @@
               builder.cls, builder.cls.mixin, constructor, substitutionMap));
         }
       }
-    } else if (supertype is InvalidTypeBuilder) {
+    } else if (supertype is InvalidTypeDeclarationBuilder) {
       builder.addSyntheticConstructor(makeDefaultConstructor(builder.cls));
     } else {
       unhandled("${supertype.runtimeType}", "installForwardingConstructors",
@@ -567,6 +562,16 @@
     return new InterfaceType(enclosingClass, typeParameterTypes);
   }
 
+  void setupTopAndBottomTypes() {
+    objectType
+        .bind(loader.coreLibrary.lookupLocalMember("Object", required: true));
+
+    ClassBuilder nullClassBuilder =
+        loader.coreLibrary.lookupLocalMember("Null", required: true);
+    nullClassBuilder.isNullClass = true;
+    bottomType.bind(nullClassBuilder);
+  }
+
   void computeCoreTypes() {
     List<Library> libraries = <Library>[];
     for (String platformLibrary in [
@@ -795,6 +800,7 @@
         environment,
         new KernelConstantErrorReporter(loader),
         desugarSets: !backendTarget.supportsSetLiterals,
+        enableTripleShift: enableTripleShift,
         errorOnUnevaluatedConstant: errorOnUnevaluatedConstant);
     ticker.logMs("Evaluated constants");
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_variable_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_variable_builder.dart
index 0268710..2fb7c13 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_variable_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_variable_builder.dart
@@ -6,7 +6,7 @@
 
 import 'package:kernel/ast.dart' show VariableDeclaration;
 
-import '../builder/declaration.dart';
+import '../builder/builder.dart';
 
 class VariableBuilder extends BuilderImpl {
   @override
diff --git a/pkg/front_end/lib/src/fasta/kernel/load_library_builder.dart b/pkg/front_end/lib/src/fasta/kernel/load_library_builder.dart
index e071810..4d053bd 100644
--- a/pkg/front_end/lib/src/fasta/kernel/load_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/load_library_builder.dart
@@ -19,7 +19,7 @@
 
 import '../source/source_library_builder.dart' show SourceLibraryBuilder;
 
-import '../builder/declaration.dart';
+import '../builder/builder.dart';
 
 import 'forest.dart' show Forest;
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart b/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
index bcceaad..552dc88 100644
--- a/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
@@ -22,18 +22,16 @@
 
 import 'package:kernel/util/graph.dart' show Graph, computeStrongComponents;
 
-import '../builder/builder.dart';
-
-import 'kernel_builder.dart'
-    show
-        ClassBuilder,
-        FormalParameterBuilder,
-        FunctionTypeBuilder,
-        NamedTypeBuilder,
-        TypeAliasBuilder,
-        TypeBuilder,
-        TypeDeclarationBuilder,
-        TypeVariableBuilder;
+import '../builder/class_builder.dart';
+import '../builder/formal_parameter_builder.dart';
+import '../builder/function_type_builder.dart';
+import '../builder/invalid_type_declaration_builder.dart';
+import '../builder/named_type_builder.dart';
+import '../builder/nullability_builder.dart';
+import '../builder/type_alias_builder.dart';
+import '../builder/type_builder.dart';
+import '../builder/type_declaration_builder.dart';
+import '../builder/type_variable_builder.dart';
 
 import '../dill/dill_class_builder.dart' show DillClassBuilder;
 
@@ -68,8 +66,11 @@
       if (declaration is ClassBuilder) {
         int result = Variance.unrelated;
         if (type.arguments != null) {
-          for (TypeBuilder argument in type.arguments) {
-            result = Variance.meet(result, computeVariance(variable, argument));
+          for (int i = 0; i < type.arguments.length; ++i) {
+            result = Variance.meet(
+                result,
+                Variance.combine(declaration.cls.typeParameters[i].variance,
+                    computeVariance(variable, type.arguments[i])));
           }
         }
         return result;
@@ -227,7 +228,7 @@
           arguments[i] = substitutedArgument;
         }
       }
-    } else if (declaration is InvalidTypeBuilder) {
+    } else if (declaration is InvalidTypeDeclarationBuilder) {
       // Don't substitute.
     } else {
       assert(false, "Unexpected named type builder declaration: $declaration.");
diff --git a/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart b/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
index d54e02f..83b88be 100644
--- a/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
@@ -21,18 +21,16 @@
         TypedefType,
         VoidType;
 
-import '../kernel/kernel_builder.dart'
-    show
-        DynamicTypeBuilder,
-        FunctionTypeBuilder,
-        ClassBuilder,
-        FormalParameterBuilder,
-        NamedTypeBuilder,
-        TypeVariableBuilder,
-        LibraryBuilder,
-        NullabilityBuilder,
-        TypeBuilder,
-        VoidTypeBuilder;
+import '../builder/class_builder.dart';
+import '../builder/dynamic_type_builder.dart';
+import '../builder/formal_parameter_builder.dart';
+import '../builder/function_type_builder.dart';
+import '../builder/library_builder.dart';
+import '../builder/named_type_builder.dart';
+import '../builder/nullability_builder.dart';
+import '../builder/type_builder.dart';
+import '../builder/type_variable_builder.dart';
+import '../builder/void_type_builder.dart';
 
 import '../loader.dart' show Loader;
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/types.dart b/pkg/front_end/lib/src/fasta/kernel/types.dart
index bf19015..d384d59 100644
--- a/pkg/front_end/lib/src/fasta/kernel/types.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/types.dart
@@ -18,6 +18,7 @@
         TypeParameter,
         TypeParameterType,
         TypedefType,
+        Variance,
         VoidType;
 
 import 'package:kernel/type_algebra.dart' show Substitution;
@@ -227,14 +228,24 @@
     throw "Unhandled type combination: ${t.runtimeType} ${s.runtimeType}";
   }
 
-  /// Returns true if all types in [s] and [t] pairwise are subtypes.
-  bool areSubtypesOfKernel(List<DartType> s, List<DartType> t) {
-    if (s.length != t.length) {
-      throw "Numbers of type arguments don't match $s $t.";
+  /// Returns true if all type arguments in [s] and [t] pairwise are subtypes
+  /// with respect to the variance of the corresponding [p] type parameter.
+  bool areTypeArgumentsOfSubtypeKernel(
+      List<DartType> s, List<DartType> t, List<TypeParameter> p) {
+    if (s.length != t.length || s.length != p.length) {
+      throw "Numbers of type arguments don't match $s $t with parameters $p.";
     }
     for (int i = 0; i < s.length; i++) {
-      if (!isSubtypeOfKernel(
-          s[i], t[i], SubtypeCheckMode.ignoringNullabilities)) return false;
+      int variance = p[i].variance;
+      if (variance == Variance.contravariant) {
+        if (!isSubtypeOfKernel(
+            t[i], s[i], SubtypeCheckMode.ignoringNullabilities)) return false;
+      } else if (variance == Variance.invariant) {
+        if (!isSameTypeKernel(s[i], t[i])) return false;
+      } else {
+        if (!isSubtypeOfKernel(
+            s[i], t[i], SubtypeCheckMode.ignoringNullabilities)) return false;
+      }
     }
     return true;
   }
@@ -297,8 +308,8 @@
     if (asSupertype == null) {
       return false;
     } else {
-      return types.areSubtypesOfKernel(
-          asSupertype.typeArguments, t.typeArguments);
+      return types.areTypeArgumentsOfSubtypeKernel(asSupertype.typeArguments,
+          t.typeArguments, t.classNode.typeParameters);
     }
   }
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/unlinked_scope.dart b/pkg/front_end/lib/src/fasta/kernel/unlinked_scope.dart
index edc3835..8463914 100644
--- a/pkg/front_end/lib/src/fasta/kernel/unlinked_scope.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/unlinked_scope.dart
@@ -2,9 +2,9 @@
 // for 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 '../builder/declaration.dart';
+import '../builder/builder.dart';
 
-import 'kernel_builder.dart' show Builder, Scope;
+import '../scope.dart';
 
 /// Scope that returns an [UnlinkedDeclaration] if a name can't be resolved.
 /// This is intended to be used as the `enclosingScope` in `BodyBuilder` to
diff --git a/pkg/front_end/lib/src/fasta/kernel/verifier.dart b/pkg/front_end/lib/src/fasta/kernel/verifier.dart
index 2762157..d6a1f87 100644
--- a/pkg/front_end/lib/src/fasta/kernel/verifier.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/verifier.dart
@@ -13,8 +13,10 @@
         ExpressionStatement,
         Field,
         FunctionType,
+        InterfaceType,
         Library,
         Member,
+        Nullability,
         Procedure,
         StaticInvocation,
         SuperMethodInvocation,
@@ -185,6 +187,19 @@
         }
       }
     }
+    super.visitFunctionType(node);
+  }
+
+  @override
+  visitInterfaceType(InterfaceType node) {
+    Uri importUri = node.classNode.enclosingLibrary.importUri;
+    if (node.classNode.name == "Null" &&
+        importUri.scheme == "dart" &&
+        importUri.path == "core" &&
+        node.nullability != Nullability.nullable) {
+      problem(null, "Found a not nullable Null type: ${node}");
+    }
+    super.visitInterfaceType(node);
   }
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/loader.dart b/pkg/front_end/lib/src/fasta/loader.dart
index 7177fc3..aaf35d3 100644
--- a/pkg/front_end/lib/src/fasta/loader.dart
+++ b/pkg/front_end/lib/src/fasta/loader.dart
@@ -10,12 +10,14 @@
 
 import 'package:kernel/ast.dart' show Class, DartType, Library;
 
-import 'builder/builder.dart'
-    show Builder, ClassBuilder, LibraryBuilder, Scope, TypeBuilder;
+import 'scope.dart';
 
-import 'builder/declaration_builder.dart' show DeclarationBuilder;
-
-import 'builder/modifier_builder.dart' show ModifierBuilder;
+import 'builder/class_builder.dart';
+import 'builder/declaration_builder.dart';
+import 'builder/library_builder.dart';
+import 'builder/member_builder.dart';
+import 'builder/modifier_builder.dart';
+import 'builder/type_builder.dart';
 
 import 'crash.dart' show firstSourceUri;
 
@@ -149,10 +151,10 @@
             }
 
             hasPackageSpecifiedLanguageVersion = true;
-            String langaugeVersionString = property.substring(5);
+            String languageVersionString = property.substring(5);
 
             // Verify that the version is x.y[whatever]
-            List<String> dotSeparatedParts = langaugeVersionString.split(".");
+            List<String> dotSeparatedParts = languageVersionString.split(".");
             if (dotSeparatedParts.length >= 2) {
               packageSpecifiedLanguageVersionMajor =
                   int.tryParse(dotSeparatedParts[0]);
@@ -312,17 +314,6 @@
 fileUri: $fileUri
 severity: $severity
 """;
-    // TODO(askesc): Swap message and context around for interface checks
-    // and mixin overrides to make comparing context here unnecessary.
-    if (context != null) {
-      for (LocatedMessage contextMessage in context) {
-        trace += """
-message: ${contextMessage.message}
-charOffset: ${contextMessage.charOffset}
-fileUri: ${contextMessage.uri}
-""";
-      }
-    }
     if (!seenMessages.add(trace)) return null;
     if (message.code.severity == Severity.context) {
       internalProblem(
@@ -346,17 +337,17 @@
     return formattedMessage;
   }
 
-  Builder getAbstractClassInstantiationError() {
+  MemberBuilder getAbstractClassInstantiationError() {
     return target.getAbstractClassInstantiationError(this);
   }
 
-  Builder getCompileTimeError() => target.getCompileTimeError(this);
+  MemberBuilder getCompileTimeError() => target.getCompileTimeError(this);
 
-  Builder getDuplicatedFieldInitializerError() {
+  MemberBuilder getDuplicatedFieldInitializerError() {
     return target.getDuplicatedFieldInitializerError(this);
   }
 
-  Builder getNativeAnnotation() => target.getNativeAnnotation(this);
+  MemberBuilder getNativeAnnotation() => target.getNativeAnnotation(this);
 
   ClassBuilder computeClassBuilderFromTargetClass(Class cls);
 
diff --git a/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart b/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
index f5e9320..16384d7 100644
--- a/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
+++ b/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart
@@ -1556,11 +1556,6 @@
   }
 
   @override
-  void handleVarianceModifier(Token variance) {
-    listener?.handleVarianceModifier(variance);
-  }
-
-  @override
   void handleVoidKeyword(Token token) {
     listener?.handleVoidKeyword(token);
   }
diff --git a/pkg/front_end/lib/src/fasta/parser/listener.dart b/pkg/front_end/lib/src/fasta/parser/listener.dart
index e5f5fad..89851cb 100644
--- a/pkg/front_end/lib/src/fasta/parser/listener.dart
+++ b/pkg/front_end/lib/src/fasta/parser/listener.dart
@@ -1231,10 +1231,6 @@
     logEvent("TypeVariables");
   }
 
-  void handleVarianceModifier(Token variance) {
-    logEvent("VarianceModifier");
-  }
-
   void reportVarianceModifierNotEnabled(Token variance) {
     if (variance != null) {
       handleRecoverableError(
diff --git a/pkg/front_end/lib/src/fasta/parser/member_kind.dart b/pkg/front_end/lib/src/fasta/parser/member_kind.dart
index 4475881..72da388 100644
--- a/pkg/front_end/lib/src/fasta/parser/member_kind.dart
+++ b/pkg/front_end/lib/src/fasta/parser/member_kind.dart
@@ -32,6 +32,12 @@
   /// A top-level method.
   TopLevelMethod,
 
+  /// A non-static method in an extension.
+  ExtensionNonStaticMethod,
+
+  /// A static method in an extension.
+  ExtensionStaticMethod,
+
   /// An instance field in a class.
   NonStaticField,
 
diff --git a/pkg/front_end/lib/src/fasta/parser/modifier_context.dart b/pkg/front_end/lib/src/fasta/parser/modifier_context.dart
index 2c11862..8d9fd2f 100644
--- a/pkg/front_end/lib/src/fasta/parser/modifier_context.dart
+++ b/pkg/front_end/lib/src/fasta/parser/modifier_context.dart
@@ -117,6 +117,10 @@
         memberKind == MemberKind.TopLevelMethod) {
       reportExtraneousModifier(this.covariantToken);
       this.covariantToken = null;
+    } else if (memberKind == MemberKind.ExtensionNonStaticMethod ||
+        memberKind == MemberKind.ExtensionStaticMethod) {
+      reportExtraneousModifierInExtension(this.covariantToken);
+      this.covariantToken = null;
     }
     if (constToken != null) {
       reportExtraneousModifier(constToken);
@@ -462,6 +466,13 @@
     }
   }
 
+  void reportExtraneousModifierInExtension(Token modifier) {
+    if (modifier != null) {
+      parser.reportRecoverableErrorWithToken(
+          modifier, fasta.templateExtraneousModifierInExtension);
+    }
+  }
+
   void reportModifierOutOfOrder(Token modifier, String beforeModifier) {
     parser.reportRecoverableError(
         modifier,
diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart
index 9e548fb..2a62ab6 100644
--- a/pkg/front_end/lib/src/fasta/parser/parser.dart
+++ b/pkg/front_end/lib/src/fasta/parser/parser.dart
@@ -1337,7 +1337,9 @@
       if (isModifier(next)) {
         if (optional('covariant', next)) {
           if (memberKind != MemberKind.StaticMethod &&
-              memberKind != MemberKind.TopLevelMethod) {
+              memberKind != MemberKind.TopLevelMethod &&
+              memberKind != MemberKind.ExtensionNonStaticMethod &&
+              memberKind != MemberKind.ExtensionStaticMethod) {
             covariantToken = token = next;
             next = token.next;
           }
@@ -3327,9 +3329,13 @@
         token,
         name,
         isGetter,
-        staticToken != null
-            ? MemberKind.StaticMethod
-            : MemberKind.NonStaticMethod);
+        kind == DeclarationKind.Extension
+            ? staticToken != null
+                ? MemberKind.ExtensionStaticMethod
+                : MemberKind.ExtensionNonStaticMethod
+            : staticToken != null
+                ? MemberKind.StaticMethod
+                : MemberKind.NonStaticMethod);
     token = parseInitializersOpt(beforeInitializers);
     if (token == beforeInitializers) beforeInitializers = null;
 
@@ -3941,13 +3947,6 @@
             varOrFinal, token, null, varOrFinal, null, false);
       }
       return parseExpressionStatementOrDeclaration(token);
-    } else if (identical(value, 'late')) {
-      Token lateToken = token.next;
-      if (!isModifier(lateToken.next)) {
-        return parseExpressionStatementOrDeclarationAfterModifiers(
-            lateToken, token, lateToken, null, null, false);
-      }
-      return parseExpressionStatementOrDeclaration(token);
     } else if (identical(value, 'if')) {
       return parseIfStatement(token);
     } else if (identical(value, 'await') && optional('for', token.next.next)) {
diff --git a/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart b/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
index de9c32d..1255e8d 100644
--- a/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
+++ b/pkg/front_end/lib/src/fasta/parser/type_info_impl.dart
@@ -1057,10 +1057,6 @@
       TypeInfo typeInfo = superTypeInfos.head;
       Token variance = variances.head;
 
-      if (variance != null) {
-        listener.handleVarianceModifier(variance);
-      }
-
       Token extendsOrSuper = null;
       Token next2 = token2.next;
       if (typeInfo != null) {
diff --git a/pkg/front_end/lib/src/fasta/scope.dart b/pkg/front_end/lib/src/fasta/scope.dart
index 8bb9bf9..361ba43 100644
--- a/pkg/front_end/lib/src/fasta/scope.dart
+++ b/pkg/front_end/lib/src/fasta/scope.dart
@@ -4,11 +4,15 @@
 
 library fasta.scope;
 
-import 'builder/builder.dart' show NameIterator, TypeVariableBuilder;
+import 'package:kernel/ast.dart' hide MapEntry;
 
-import 'builder/declaration.dart';
-
+import 'builder/builder.dart';
+import 'builder/class_builder.dart';
 import 'builder/extension_builder.dart';
+import 'builder/library_builder.dart';
+import 'builder/member_builder.dart';
+import 'builder/name_iterator.dart';
+import 'builder/type_variable_builder.dart';
 
 import 'fasta_codes.dart'
     show
@@ -392,6 +396,32 @@
   }
 }
 
+class ConstructorScope {
+  /// Constructors declared in this scope.
+  final Map<String, MemberBuilder> local;
+
+  final String className;
+
+  ConstructorScope(this.className, this.local);
+
+  void forEach(f(String name, MemberBuilder member)) {
+    local.forEach(f);
+  }
+
+  Builder lookup(String name, int charOffset, Uri fileUri) {
+    Builder builder = local[name];
+    if (builder == null) return null;
+    if (builder.next != null) {
+      return new AmbiguousMemberBuilder(
+          name.isEmpty ? className : name, builder, charOffset, fileUri);
+    } else {
+      return builder;
+    }
+  }
+
+  String toString() => "ConstructorScope($className, ${local.keys})";
+}
+
 class ScopeBuilder {
   final Scope scope;
 
@@ -412,6 +442,18 @@
   Builder operator [](String name) => scope.local[name];
 }
 
+class ConstructorScopeBuilder {
+  final ConstructorScope scope;
+
+  ConstructorScopeBuilder(this.scope);
+
+  void addMember(String name, Builder builder) {
+    scope.local[name] = builder;
+  }
+
+  MemberBuilder operator [](String name) => scope.local[name];
+}
+
 abstract class ProblemBuilder extends BuilderImpl {
   final String name;
 
@@ -503,6 +545,50 @@
   }
 }
 
+class AmbiguousMemberBuilder extends AmbiguousBuilder implements MemberBuilder {
+  AmbiguousMemberBuilder(
+      String name, Builder builder, int charOffset, Uri fileUri)
+      : super(name, builder, charOffset, fileUri);
+
+  Member get target => null;
+
+  Member get member => null;
+
+  bool get isNative => false;
+
+  ClassBuilder get classBuilder => parent is ClassBuilder ? parent : null;
+
+  void set parent(Builder value) {
+    throw new UnsupportedError('AmbiguousMemberBuilder.parent=');
+  }
+
+  LibraryBuilder get library {
+    throw new UnsupportedError('AmbiguousMemberBuilder.parent=');
+  }
+
+  // TODO(johnniwinther): Remove this and create a [ProcedureBuilder] interface.
+  Member get extensionTearOff => null;
+
+  // TODO(johnniwinther): Remove this and create a [ProcedureBuilder] interface.
+  Procedure get procedure => null;
+
+  // TODO(johnniwinther): Remove this and create a [ProcedureBuilder] interface.
+  ProcedureKind get kind => null;
+
+  void buildOutlineExpressions(LibraryBuilder library) {
+    throw new UnsupportedError(
+        'AmbiguousMemberBuilder.buildOutlineExpressions');
+  }
+
+  void inferType() {
+    throw new UnsupportedError('AmbiguousMemberBuilder.inferType');
+  }
+
+  void inferCopiedType(covariant Object other) {
+    throw new UnsupportedError('AmbiguousMemberBuilder.inferCopiedType');
+  }
+}
+
 class ScopeLocalDeclarationIterator implements Iterator<Builder> {
   Iterator<Builder> local;
   final Iterator<Builder> setters;
diff --git a/pkg/front_end/lib/src/fasta/severity.dart b/pkg/front_end/lib/src/fasta/severity.dart
index 71f1cd6..fd9b59e 100644
--- a/pkg/front_end/lib/src/fasta/severity.dart
+++ b/pkg/front_end/lib/src/fasta/severity.dart
@@ -7,8 +7,6 @@
 enum Severity {
   context,
   error,
-  // TODO(johnniwinther): Remove legacy warning.
-  errorLegacyWarning,
   ignored,
   internalProblem,
   warning,
@@ -17,7 +15,6 @@
 const Map<String, String> severityEnumNames = const <String, String>{
   'CONTEXT': 'context',
   'ERROR': 'error',
-  'ERROR_LEGACY_WARNING': 'errorLegacyWarning',
   'IGNORED': 'ignored',
   'INTERNAL_PROBLEM': 'internalProblem',
   'WARNING': 'warning',
@@ -26,7 +23,6 @@
 const Map<String, Severity> severityEnumValues = const <String, Severity>{
   'CONTEXT': Severity.context,
   'ERROR': Severity.error,
-  'ERROR_LEGACY_WARNING': Severity.errorLegacyWarning,
   'IGNORED': Severity.ignored,
   'INTERNAL_PROBLEM': Severity.internalProblem,
   'WARNING': Severity.warning,
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 10bb91e..0ac91d5 100644
--- a/pkg/front_end/lib/src/fasta/source/diet_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/diet_listener.dart
@@ -23,8 +23,17 @@
 import '../../scanner/token.dart' show Token;
 
 import '../builder/builder.dart';
-
+import '../builder/class_builder.dart';
 import '../builder/declaration_builder.dart';
+import '../builder/formal_parameter_builder.dart';
+import '../builder/function_builder.dart';
+import '../builder/function_type_builder.dart';
+import '../builder/metadata_builder.dart';
+import '../builder/modifier_builder.dart';
+import '../builder/type_alias_builder.dart';
+import '../builder/type_builder.dart';
+
+import '../identifiers.dart' show QualifiedName;
 
 import '../constant_context.dart' show ConstantContext;
 
@@ -42,15 +51,18 @@
 
 import '../kernel/body_builder.dart' show BodyBuilder;
 
-import '../kernel/kernel_builder.dart'
-    show FormalParameterBuilder, TypeAliasBuilder, TypeBuilder;
-
 import '../parser.dart'
     show Assert, DeclarationKind, MemberKind, Parser, optional;
 
 import '../problems.dart'
     show DebugAbort, internalProblem, unexpected, unhandled;
 
+import '../quote.dart' show unescapeString;
+
+import '../scope.dart';
+
+import '../source/value_kinds.dart';
+
 import '../type_inference/type_inference_engine.dart' show TypeInferenceEngine;
 
 import '../type_inference/type_inferrer.dart' show TypeInferrer;
@@ -60,10 +72,6 @@
 import 'stack_listener.dart'
     show FixedNullableList, NullValue, ParserRecovery, StackListener;
 
-import '../source/value_kinds.dart';
-
-import '../quote.dart' show unescapeString;
-
 class DietListener extends StackListener {
   final SourceLibraryBuilder libraryBuilder;
 
@@ -555,11 +563,6 @@
   }
 
   @override
-  void handleVarianceModifier(Token variance) {
-    debugEvent("VarianceModifier");
-  }
-
-  @override
   void endConstructorReference(
       Token start, Token periodBeforeName, Token endToken) {
     debugEvent("ConstructorReference");
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 0377599..ca92153 100644
--- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
@@ -4,9 +4,21 @@
 
 library fasta.outline_builder;
 
-import 'package:kernel/ast.dart' show ProcedureKind, Variance;
+import 'package:kernel/ast.dart' show InvalidType, ProcedureKind, Variance;
 
-import '../builder/builder.dart';
+import '../builder/constructor_reference_builder.dart';
+import '../builder/enum_builder.dart';
+import '../builder/fixed_type_builder.dart';
+import '../builder/formal_parameter_builder.dart';
+import '../builder/function_type_builder.dart';
+import '../builder/invalid_type_declaration_builder.dart';
+import '../builder/metadata_builder.dart';
+import '../builder/mixin_application_builder.dart';
+import '../builder/named_type_builder.dart';
+import '../builder/nullability_builder.dart';
+import '../builder/type_builder.dart';
+import '../builder/type_variable_builder.dart';
+import '../builder/unresolved_type.dart';
 
 import '../combinator.dart' show Combinator;
 
@@ -35,15 +47,9 @@
         templateOperatorParameterMismatch1,
         templateOperatorParameterMismatch2;
 
-import '../ignored_parser_errors.dart' show isIgnoredParserError;
+import '../identifiers.dart' show QualifiedName, flattenName;
 
-// TODO(ahe): The outline isn't supposed to import kernel-specific builders.
-import '../kernel/kernel_builder.dart'
-    show
-        MetadataBuilder,
-        MixinApplicationBuilder,
-        NamedTypeBuilder,
-        TypeBuilder;
+import '../ignored_parser_errors.dart' show isIgnoredParserError;
 
 import '../kernel/type_algorithms.dart';
 
@@ -671,7 +677,10 @@
     ]));
     debugEvent("endExtensionDeclaration");
     String documentationComment = getDocumentationComment(extensionKeyword);
-    TypeBuilder supertype = pop();
+    Object onType = pop();
+    if (onType is ParserRecovery) {
+      onType = new FixedTypeBuilder(const InvalidType());
+    }
     List<TypeVariableBuilder> typeVariables = pop(NullValue.TypeVariables);
     int nameOffset = pop();
     String name = pop(NullValue.Name);
@@ -691,7 +700,7 @@
         0,
         name,
         typeVariables,
-        supertype,
+        onType,
         startOffset,
         nameOffset,
         endToken.charOffset);
@@ -1583,6 +1592,9 @@
     if (typeParameters != null) {
       typeParameters[index].bound = bound;
       if (variance != null) {
+        if (!library.loader.target.enableVariance) {
+          reportVarianceModifierNotEnabled(variance);
+        }
         typeParameters[index].variance = Variance.fromString(variance.lexeme);
       }
     }
@@ -1637,7 +1649,7 @@
             addProblem(message, builder.charOffset, builder.name.length);
             builder.bound = new NamedTypeBuilder(
                 builder.name, const NullabilityBuilder.omitted(), null)
-              ..bind(new InvalidTypeBuilder(
+              ..bind(new InvalidTypeDeclarationBuilder(
                   builder.name,
                   message.withLocation(
                       uri, builder.charOffset, builder.name.length)));
@@ -1654,13 +1666,6 @@
   }
 
   @override
-  void handleVarianceModifier(Token variance) {
-    if (!library.loader.target.enableVariance) {
-      reportVarianceModifierNotEnabled(variance);
-    }
-  }
-
-  @override
   void endPartOf(
       Token partKeyword, Token ofKeyword, Token semicolon, bool hasName) {
     debugEvent("endPartOf");
diff --git a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
index 0800b4b..f55df6f 100644
--- a/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_class_builder.dart
@@ -7,7 +7,18 @@
 import 'package:kernel/ast.dart'
     show Class, Constructor, Member, Supertype, TreeNode;
 
+import '../builder/builder.dart';
 import '../builder/class_builder.dart';
+import '../builder/constructor_reference_builder.dart';
+import '../builder/field_builder.dart';
+import '../builder/function_builder.dart';
+import '../builder/invalid_type_declaration_builder.dart';
+import '../builder/library_builder.dart';
+import '../builder/metadata_builder.dart';
+import '../builder/named_type_builder.dart';
+import '../builder/nullability_builder.dart';
+import '../builder/type_builder.dart';
+import '../builder/type_variable_builder.dart';
 
 import '../dill/dill_member_builder.dart' show DillMemberBuilder;
 
@@ -19,31 +30,17 @@
         templateConflictsWithConstructor,
         templateConflictsWithFactory,
         templateConflictsWithMember,
-        templateConflictsWithMemberWarning,
         templateConflictsWithSetter,
-        templateConflictsWithSetterWarning,
         templateSupertypeIsIllegal;
 
-import '../kernel/kernel_builder.dart'
-    show
-        ConstructorReferenceBuilder,
-        Builder,
-        FieldBuilder,
-        FunctionBuilder,
-        InvalidTypeBuilder,
-        NamedTypeBuilder,
-        LibraryBuilder,
-        MetadataBuilder,
-        NullabilityBuilder,
-        Scope,
-        TypeBuilder,
-        TypeVariableBuilder,
-        compareProcedures;
+import '../kernel/kernel_builder.dart' show compareProcedures;
 
 import '../kernel/type_algorithms.dart' show Variance, computeVariance;
 
 import '../problems.dart' show unexpected, unhandled;
 
+import '../scope.dart';
+
 import 'source_library_builder.dart' show SourceLibraryBuilder;
 
 Class initializeClass(
@@ -92,7 +89,7 @@
       List<TypeBuilder> interfaces,
       List<TypeBuilder> onTypes,
       Scope scope,
-      Scope constructors,
+      ConstructorScope constructors,
       LibraryBuilder parent,
       this.constructorReferences,
       int startCharOffset,
@@ -217,20 +214,11 @@
               member.isRegularMethod && member.isStatic && setter.isStatic)) {
         return;
       }
-      if (member.isDeclarationInstanceMember ==
-          setter.isDeclarationInstanceMember) {
-        addProblem(templateConflictsWithMember.withArguments(name),
-            setter.charOffset, noLength);
-        // TODO(ahe): Context argument to previous message?
-        addProblem(templateConflictsWithSetter.withArguments(name),
-            member.charOffset, noLength);
-      } else {
-        addProblem(templateConflictsWithMemberWarning.withArguments(name),
-            setter.charOffset, noLength);
-        // TODO(ahe): Context argument to previous message?
-        addProblem(templateConflictsWithSetterWarning.withArguments(name),
-            member.charOffset, noLength);
-      }
+      addProblem(templateConflictsWithMember.withArguments(name),
+          setter.charOffset, noLength);
+      // TODO(ahe): Context argument to previous message?
+      addProblem(templateConflictsWithSetter.withArguments(name),
+          member.charOffset, noLength);
     });
 
     scope.setters.forEach((String name, Builder setter) {
@@ -251,8 +239,7 @@
     Message message;
     for (int i = 0; i < typeVariables.length; ++i) {
       int variance = computeVariance(typeVariables[i], supertype);
-      if (variance == Variance.contravariant ||
-          variance == Variance.invariant) {
+      if (!Variance.greaterThanOrEqual(variance, typeVariables[i].variance)) {
         message = templateBadTypeVariableInSupertype.withArguments(
             typeVariables[i].name, supertype.name);
         library.addProblem(message, charOffset, noLength, fileUri);
@@ -261,7 +248,7 @@
     if (message != null) {
       return new NamedTypeBuilder(
           supertype.name, const NullabilityBuilder.omitted(), null)
-        ..bind(new InvalidTypeBuilder(supertype.name,
+        ..bind(new InvalidTypeDeclarationBuilder(supertype.name,
             message.withLocation(fileUri, charOffset, noLength)));
     }
     return supertype;
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 36ca7a8..118f28d 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
@@ -3,28 +3,34 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'dart:core' hide MapEntry;
+
 import 'package:kernel/ast.dart';
+
 import '../../base/common.dart';
-import '../builder/declaration.dart';
+
+import '../builder/builder.dart';
+import '../builder/class_builder.dart';
 import '../builder/extension_builder.dart';
+import '../builder/field_builder.dart';
 import '../builder/library_builder.dart';
 import '../builder/metadata_builder.dart';
 import '../builder/procedure_builder.dart';
 import '../builder/type_builder.dart';
 import '../builder/type_variable_builder.dart';
-import '../scope.dart';
-import '../kernel/kernel_builder.dart';
-import '../problems.dart';
+
 import '../fasta_codes.dart'
     show
         messagePatchDeclarationMismatch,
         messagePatchDeclarationOrigin,
         noLength,
         templateConflictsWithMember,
-        templateConflictsWithMemberWarning,
         templateConflictsWithSetter,
-        templateConflictsWithSetterWarning,
         templateExtensionMemberConflictsWithObjectMember;
+
+import '../problems.dart';
+
+import '../scope.dart';
+
 import 'source_library_builder.dart';
 
 class SourceExtensionBuilder extends ExtensionBuilderImpl {
@@ -152,24 +158,27 @@
 
     scope.setters.forEach((String name, Builder setter) {
       Builder member = scopeBuilder[name];
-      if (member == null ||
-          !(member.isField && !member.isFinal && !member.isConst ||
-              member.isRegularMethod && member.isStatic && setter.isStatic)) {
+      if (member == null) {
+        // Setter without getter.
         return;
       }
-      if (member.isDeclarationInstanceMember ==
-          setter.isDeclarationInstanceMember) {
+      bool conflict = member.isDeclarationInstanceMember !=
+          setter.isDeclarationInstanceMember;
+      if (member.isField) {
+        if (!member.isConst && !member.isFinal) {
+          // Setter with writable field.
+          conflict = true;
+        }
+      } else if (member.isRegularMethod) {
+        // Setter with method.
+        conflict = true;
+      }
+      if (conflict) {
         addProblem(templateConflictsWithMember.withArguments(name),
             setter.charOffset, noLength);
         // TODO(ahe): Context argument to previous message?
         addProblem(templateConflictsWithSetter.withArguments(name),
             member.charOffset, noLength);
-      } else {
-        addProblem(templateConflictsWithMemberWarning.withArguments(name),
-            setter.charOffset, noLength);
-        // TODO(ahe): Context argument to previous message?
-        addProblem(templateConflictsWithSetterWarning.withArguments(name),
-            member.charOffset, noLength);
       }
     });
 
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 00f980e..52f6b65 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
@@ -6,6 +6,7 @@
 
 import 'dart:convert' show jsonEncode;
 
+import 'package:front_end/src/fasta/kernel/kernel_shadow_ast.dart';
 import 'package:kernel/ast.dart'
     show
         Arguments,
@@ -58,31 +59,34 @@
 
 import '../../scanner/token.dart' show Token;
 
-import '../builder/builder.dart'
-    show
-        Builder,
-        ClassBuilder,
-        ConstructorReferenceBuilder,
-        EnumConstantInfo,
-        FormalParameterBuilder,
-        FunctionTypeBuilder,
-        MemberBuilder,
-        MetadataBuilder,
-        NameIterator,
-        PrefixBuilder,
-        FunctionBuilder,
-        NullabilityBuilder,
-        QualifiedName,
-        Scope,
-        TypeBuilder,
-        TypeDeclarationBuilder,
-        TypeVariableBuilder,
-        UnresolvedType,
-        flattenName;
-
+import '../builder/builder.dart';
+import '../builder/builtin_type_builder.dart';
+import '../builder/class_builder.dart';
+import '../builder/constructor_builder.dart';
+import '../builder/constructor_reference_builder.dart';
+import '../builder/dynamic_type_builder.dart';
+import '../builder/enum_builder.dart';
 import '../builder/extension_builder.dart';
-
+import '../builder/field_builder.dart';
+import '../builder/formal_parameter_builder.dart';
+import '../builder/function_builder.dart';
+import '../builder/function_type_builder.dart';
+import '../builder/invalid_type_declaration_builder.dart';
 import '../builder/library_builder.dart';
+import '../builder/member_builder.dart';
+import '../builder/metadata_builder.dart';
+import '../builder/mixin_application_builder.dart';
+import '../builder/name_iterator.dart';
+import '../builder/named_type_builder.dart';
+import '../builder/nullability_builder.dart';
+import '../builder/prefix_builder.dart';
+import '../builder/procedure_builder.dart';
+import '../builder/type_alias_builder.dart';
+import '../builder/type_builder.dart';
+import '../builder/type_declaration_builder.dart';
+import '../builder/type_variable_builder.dart';
+import '../builder/unresolved_type.dart';
+import '../builder/void_type_builder.dart';
 
 import '../combinator.dart' show Combinator;
 
@@ -151,43 +155,14 @@
         templatePatchInjectionFailed,
         templateTypeVariableDuplicatedNameCause;
 
+import '../identifiers.dart' show QualifiedName, flattenName;
+
 import '../import.dart' show Import;
 
 import '../kernel/kernel_builder.dart'
     show
-        AccessErrorBuilder,
-        BuiltinTypeBuilder,
-        ClassBuilder,
-        ConstructorReferenceBuilder,
-        Builder,
-        DynamicTypeBuilder,
-        EnumConstantInfo,
-        FormalParameterBuilder,
-        FunctionTypeBuilder,
         ImplicitFieldType,
-        InvalidTypeBuilder,
-        ConstructorBuilder,
-        EnumBuilder,
-        FunctionBuilder,
-        TypeAliasBuilder,
-        FieldBuilder,
-        MixinApplicationBuilder,
-        NamedTypeBuilder,
-        ProcedureBuilder,
-        RedirectingFactoryBuilder,
-        LibraryBuilder,
         LoadLibraryBuilder,
-        MemberBuilder,
-        MetadataBuilder,
-        NameIterator,
-        PrefixBuilder,
-        QualifiedName,
-        Scope,
-        TypeBuilder,
-        TypeDeclarationBuilder,
-        TypeVariableBuilder,
-        UnresolvedType,
-        VoidTypeBuilder,
         compareProcedures,
         toKernelCombinators;
 
@@ -219,6 +194,8 @@
 
 import '../problems.dart' show unexpected, unhandled;
 
+import '../scope.dart';
+
 import '../severity.dart' show Severity;
 
 import '../type_inference/type_inferrer.dart' show TypeInferrerImpl;
@@ -229,6 +206,10 @@
 
 import 'source_loader.dart' show SourceLoader;
 
+// TODO(johnniwinther,jensj): Replace this with the correct scheme.
+const int enableNonNullableDefaultMajorVersion = 2;
+const int enableNonNullableDefaultMinorVersion = 6;
+
 class SourceLibraryBuilder extends LibraryBuilderImpl {
   static const String MALFORMED_URI_SCHEME = "org-dartlang-malformed-uri";
 
@@ -382,6 +363,13 @@
     return type;
   }
 
+  // TODO(38287): Compute the predicate using the library version instead.
+  @override
+  bool get isNonNullableByDefault =>
+      loader.target.enableNonNullable &&
+      library.languageVersionMajor >= enableNonNullableDefaultMajorVersion &&
+      library.languageVersionMinor >= enableNonNullableDefaultMinorVersion;
+
   @override
   void setLanguageVersion(int major, int minor,
       {int offset: 0, int length: noLength, bool explicit: false}) {
@@ -394,7 +382,7 @@
       return;
     }
 
-    // If trying to set a langauge version that is higher than the current sdk
+    // If trying to set a language version that is higher than the current sdk
     // version it's an error.
     if (major > loader.target.currentSdkVersionMajor ||
         (major == loader.target.currentSdkVersionMajor &&
@@ -806,6 +794,8 @@
           isConst: true));
     }
 
+    library.isNonNullableByDefault = isNonNullableByDefault;
+
     return library;
   }
 
@@ -1049,7 +1039,7 @@
             break;
 
           default:
-            if (member is InvalidTypeBuilder) {
+            if (member is InvalidTypeDeclarationBuilder) {
               unserializableExports ??= <String, String>{};
               unserializableExports[name] = member.message.message;
             } else {
@@ -1314,8 +1304,8 @@
 
     // When looking up a constructor, we don't consider type variables or the
     // library scope.
-    Scope constructorScope = new Scope(
-        local: constructors, debugName: className, isModifiable: false);
+    ConstructorScope constructorScope =
+        new ConstructorScope(className, constructors);
     bool isMixinDeclaration = false;
     if (modifiers & mixinDeclarationMask != 0) {
       isMixinDeclaration = true;
@@ -1691,10 +1681,7 @@
                 parent: scope.withTypeVariables(typeVariables),
                 debugName: "mixin $fullname ",
                 isModifiable: false),
-            new Scope(
-                local: <String, MemberBuilder>{},
-                debugName: fullname,
-                isModifiable: false),
+            new ConstructorScope(fullname, <String, MemberBuilder>{}),
             this,
             <ConstructorReferenceBuilder>[],
             computedStartCharOffset,
@@ -1758,7 +1745,7 @@
     if (hasInitializer) {
       modifiers |= hasInitializerMask;
     }
-    FieldBuilder fieldBuilder = new FieldBuilder(
+    FieldBuilderImpl fieldBuilder = new FieldBuilderImpl(
         metadata, type, name, modifiers, this, charOffset, charEndOffset);
     fieldBuilder.constInitializerToken = constInitializerToken;
     addBuilder(name, fieldBuilder, charOffset);
@@ -1787,7 +1774,7 @@
       String nativeMethodName,
       {Token beginInitializers}) {
     MetadataCollector metadataCollector = loader.target.metadataCollector;
-    ConstructorBuilder constructorBuilder = new ConstructorBuilder(
+    ConstructorBuilder constructorBuilder = new ConstructorBuilderImpl(
         metadata,
         modifiers & ~abstractMask,
         returnType,
@@ -1842,7 +1829,7 @@
         returnType = addVoidType(charOffset);
       }
     }
-    ProcedureBuilder procedureBuilder = new ProcedureBuilder(
+    ProcedureBuilder procedureBuilder = new ProcedureBuilderImpl(
         metadata,
         modifiers,
         returnType,
@@ -1916,7 +1903,7 @@
           nativeMethodName,
           redirectionTarget);
     } else {
-      procedureBuilder = new ProcedureBuilder(
+      procedureBuilder = new ProcedureBuilderImpl(
           metadata,
           staticMask | modifiers,
           returnType,
@@ -2108,15 +2095,15 @@
   }
 
   void addNativeDependency(String nativeImportPath) {
-    Builder constructor = loader.getNativeAnnotation();
+    MemberBuilder constructor = loader.getNativeAnnotation();
     Arguments arguments =
         new Arguments(<Expression>[new StringLiteral(nativeImportPath)]);
     Expression annotation;
     if (constructor.isConstructor) {
-      annotation = new ConstructorInvocation(constructor.target, arguments)
+      annotation = new ConstructorInvocation(constructor.member, arguments)
         ..isConst = true;
     } else {
-      annotation = new StaticInvocation(constructor.target, arguments)
+      annotation = new StaticInvocation(constructor.member, arguments)
         ..isConst = true;
     }
     library.addAnnotation(annotation);
@@ -2175,8 +2162,8 @@
       {bool isExport: false, bool isImport: false}) {
     // TODO(ahe): Can I move this to Scope or Prefix?
     if (declaration == other) return declaration;
-    if (declaration is InvalidTypeBuilder) return declaration;
-    if (other is InvalidTypeBuilder) return other;
+    if (declaration is InvalidTypeDeclarationBuilder) return declaration;
+    if (other is InvalidTypeDeclarationBuilder) return other;
     if (declaration is AccessErrorBuilder) {
       AccessErrorBuilder error = declaration;
       declaration = error.builder;
@@ -2265,7 +2252,7 @@
     // We report the error lazily (setting suppressMessage to false) because the
     // spec 18.1 states that 'It is not an error if N is introduced by two or
     // more imports but never referred to.'
-    return new InvalidTypeBuilder(
+    return new InvalidTypeDeclarationBuilder(
         name, message.withLocation(fileUri, charOffset, name.length),
         suppressMessage: false);
   }
@@ -2360,7 +2347,8 @@
       TypeVariableBuilder newVariable = new TypeVariableBuilder(
           variable.name, this, variable.charOffset,
           bound: variable.bound?.clone(newTypes),
-          isExtensionTypeParameter: isExtensionTypeParameter);
+          isExtensionTypeParameter: isExtensionTypeParameter,
+          variableVariance: variable.variance);
       copy.add(newVariable);
       boundlessTypeVariables.add(newVariable);
     }
@@ -2552,13 +2540,20 @@
 
   void reportTypeArgumentIssues(
       List<TypeArgumentIssue> issues, Uri fileUri, int offset,
-      {bool inferred, DartType targetReceiver, String targetName}) {
+      {bool inferred,
+      TypeArgumentsInfo typeArgumentsInfo,
+      DartType targetReceiver,
+      String targetName}) {
     for (TypeArgumentIssue issue in issues) {
       DartType argument = issue.argument;
       TypeParameter typeParameter = issue.typeParameter;
 
       Message message;
-      bool issueInferred = inferred ?? inferredTypes.contains(argument);
+      bool issueInferred = inferred ??
+          typeArgumentsInfo?.isInferred(issue.index) ??
+          inferredTypes.contains(argument);
+      offset =
+          typeArgumentsInfo?.getOffsetForIndex(issue.index, offset) ?? offset;
       if (argument is FunctionType && argument.typeParameters.length > 0) {
         if (issueInferred) {
           message = templateGenericFunctionTypeInferredAsActualTypeArgument
@@ -2774,8 +2769,10 @@
   }
 
   void checkBoundsInStaticInvocation(
-      StaticInvocation node, TypeEnvironment typeEnvironment, Uri fileUri,
-      {bool inferred = false}) {
+      StaticInvocation node,
+      TypeEnvironment typeEnvironment,
+      Uri fileUri,
+      TypeArgumentsInfo typeArgumentsInfo) {
     // TODO(johnniwinther): Handle partially inferred type arguments in
     // extension method calls. Currently all are considered inferred in the
     // error messages.
@@ -2794,7 +2791,7 @@
       }
       String targetName = node.target.name.name;
       reportTypeArgumentIssues(issues, fileUri, node.fileOffset,
-          inferred: inferred,
+          typeArgumentsInfo: typeArgumentsInfo,
           targetReceiver: targetReceiver,
           targetName: targetName);
     }
@@ -2809,8 +2806,7 @@
       Member interfaceTarget,
       Arguments arguments,
       Uri fileUri,
-      int offset,
-      {bool inferred = false}) {
+      int offset) {
     if (arguments.types.isEmpty) return;
     Class klass;
     List<DartType> receiverTypeArguments;
@@ -2854,7 +2850,7 @@
         instantiatedMethodParameters, arguments.types, typeEnvironment);
     if (issues != null) {
       reportTypeArgumentIssues(issues, fileUri, offset,
-          inferred: inferred,
+          typeArgumentsInfo: getTypeArgumentsInfo(arguments),
           targetReceiver: receiverType,
           targetName: name.name);
     }
@@ -3114,6 +3110,7 @@
         // parent declaration.
         parent.addType(type);
       } else if (nameOrQualified is QualifiedName) {
+        NamedTypeBuilder builder = type.builder;
         // Attempt to use a member or type variable as a prefix.
         Message message = templateNotAPrefixInTypeAnnotation.withArguments(
             flattenName(
@@ -3121,10 +3118,9 @@
             nameOrQualified.name);
         library.addProblem(message, type.charOffset,
             nameOrQualified.endCharOffset - type.charOffset, type.fileUri);
-        type.builder.bind(type.builder.buildInvalidType(message.withLocation(
-            type.fileUri,
-            type.charOffset,
-            nameOrQualified.endCharOffset - type.charOffset)));
+        builder.bind(builder.buildInvalidTypeDeclarationBuilder(
+            message.withLocation(type.fileUri, type.charOffset,
+                nameOrQualified.endCharOffset - type.charOffset)));
       } else {
         scope ??= toScope(null).withTypeVariables(typeVariables);
         type.resolveIn(scope, library);
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 bc077b2..1abdee5 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -37,7 +37,17 @@
 
 import '../blacklisted_classes.dart' show blacklistedCoreClasses;
 
+import '../builder/builder.dart';
+import '../builder/class_builder.dart';
+import '../builder/enum_builder.dart';
 import '../builder/extension_builder.dart';
+import '../builder/field_builder.dart';
+import '../builder/library_builder.dart';
+import '../builder/member_builder.dart';
+import '../builder/named_type_builder.dart';
+import '../builder/procedure_builder.dart';
+import '../builder/type_builder.dart';
+import '../builder/type_declaration_builder.dart';
 
 import '../export.dart' show Export;
 
@@ -73,20 +83,7 @@
 import '../kernel/kernel_shadow_ast.dart' show ShadowTypeInferenceEngine;
 
 import '../kernel/kernel_builder.dart'
-    show
-        ClassBuilder,
-        ClassHierarchyBuilder,
-        Builder,
-        DelayedMember,
-        DelayedOverrideCheck,
-        EnumBuilder,
-        FieldBuilder,
-        ProcedureBuilder,
-        LibraryBuilder,
-        MemberBuilder,
-        NamedTypeBuilder,
-        TypeBuilder,
-        TypeDeclarationBuilder;
+    show ClassHierarchyBuilder, DelayedMember, DelayedOverrideCheck;
 
 import '../kernel/kernel_target.dart' show KernelTarget;
 
@@ -335,8 +332,8 @@
               "debugExpression in $enclosingClass");
       }
     }
-    ProcedureBuilder builder = new ProcedureBuilder(null, 0, null, "debugExpr",
-        null, null, ProcedureKind.Method, library, 0, 0, -1, -1)
+    ProcedureBuilder builder = new ProcedureBuilderImpl(null, 0, null,
+        "debugExpr", null, null, ProcedureKind.Method, library, 0, 0, -1, -1)
       ..parent = parent;
     BodyBuilder listener = dietListener.createListener(
         builder, dietListener.memberScope,
diff --git a/pkg/front_end/lib/src/fasta/source/type_promotion_look_ahead_listener.dart b/pkg/front_end/lib/src/fasta/source/type_promotion_look_ahead_listener.dart
index ad16fe4..69e5e57 100644
--- a/pkg/front_end/lib/src/fasta/source/type_promotion_look_ahead_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/type_promotion_look_ahead_listener.dart
@@ -4,7 +4,7 @@
 
 library fasta.type_promotion_look_ahead_listener;
 
-import '../builder/declaration.dart';
+import '../builder/builder.dart';
 
 import '../messages.dart' show LocatedMessage, Message, MessageCode;
 
@@ -1328,11 +1328,6 @@
   }
 
   @override
-  void handleVarianceModifier(Token variance) {
-    debugEvent("VarianceModifier", variance);
-  }
-
-  @override
   void handleNoTypeVariables(Token token) {
     debugEvent("NoTypeVariables", token);
   }
diff --git a/pkg/front_end/lib/src/fasta/source/value_kinds.dart b/pkg/front_end/lib/src/fasta/source/value_kinds.dart
index aff85ed..49039ab 100644
--- a/pkg/front_end/lib/src/fasta/source/value_kinds.dart
+++ b/pkg/front_end/lib/src/fasta/source/value_kinds.dart
@@ -5,6 +5,33 @@
 import 'package:kernel/ast.dart' as type;
 
 import '../builder/builder.dart' as type;
+import '../builder/builtin_type_builder.dart' as type;
+import '../builder/class_builder.dart' as type;
+import '../builder/constructor_reference_builder.dart' as type;
+import '../builder/dynamic_type_builder.dart' as type;
+import '../builder/enum_builder.dart' as type;
+import '../builder/field_builder.dart' as type;
+import '../builder/formal_parameter_builder.dart' as type;
+import '../builder/function_builder.dart' as type;
+import '../builder/function_type_builder.dart' as type;
+import '../builder/invalid_type_declaration_builder.dart' as type;
+import '../builder/library_builder.dart' as type;
+import '../builder/member_builder.dart' as type;
+import '../builder/metadata_builder.dart' as type;
+import '../builder/mixin_application_builder.dart' as type;
+import '../builder/modifier_builder.dart' as type;
+import '../builder/name_iterator.dart' as type;
+import '../builder/named_type_builder.dart' as type;
+import '../builder/nullability_builder.dart' as type;
+import '../builder/prefix_builder.dart' as type;
+import '../builder/type_alias_builder.dart' as type;
+import '../builder/type_builder.dart' as type;
+import '../builder/type_declaration_builder.dart' as type;
+import '../builder/type_variable_builder.dart' as type;
+import '../builder/unresolved_type.dart' as type;
+import '../builder/void_type_builder.dart' as type;
+
+import '../identifiers.dart' as type;
 
 import '../kernel/expression_generator.dart' as type;
 
diff --git a/pkg/front_end/lib/src/fasta/target_implementation.dart b/pkg/front_end/lib/src/fasta/target_implementation.dart
index d0506c9..e3470f7 100644
--- a/pkg/front_end/lib/src/fasta/target_implementation.dart
+++ b/pkg/front_end/lib/src/fasta/target_implementation.dart
@@ -10,7 +10,9 @@
 
 import '../base/processed_options.dart' show ProcessedOptions;
 
-import 'builder/builder.dart' show Builder, ClassBuilder, LibraryBuilder;
+import 'builder/class_builder.dart';
+import 'builder/library_builder.dart';
+import 'builder/member_builder.dart';
 
 import 'compiler_context.dart' show CompilerContext;
 
@@ -41,12 +43,10 @@
   /// Shared with [CompilerContext].
   final Map<Uri, Source> uriToSource = CompilerContext.current.uriToSource;
 
-  Builder cachedAbstractClassInstantiationError;
-  Builder cachedCompileTimeError;
-  Builder cachedDuplicatedFieldInitializerError;
-  Builder cachedFallThroughError;
-  Builder cachedNativeAnnotation;
-  Builder cachedNativeExtensionAnnotation;
+  MemberBuilder cachedAbstractClassInstantiationError;
+  MemberBuilder cachedCompileTimeError;
+  MemberBuilder cachedDuplicatedFieldInitializerError;
+  MemberBuilder cachedNativeAnnotation;
 
   bool enableExtensionMethods;
   bool enableNonNullable;
@@ -85,7 +85,7 @@
   /// [AbstractClassInstantiationError] error.  The constructor is expected to
   /// accept a single argument of type String, which is the name of the
   /// abstract class.
-  Builder getAbstractClassInstantiationError(Loader loader) {
+  MemberBuilder getAbstractClassInstantiationError(Loader loader) {
     if (cachedAbstractClassInstantiationError != null) {
       return cachedAbstractClassInstantiationError;
     }
@@ -96,7 +96,7 @@
   /// Returns a reference to the constructor used for creating a compile-time
   /// error. The constructor is expected to accept a single argument of type
   /// String, which is the compile-time error message.
-  Builder getCompileTimeError(Loader loader) {
+  MemberBuilder getCompileTimeError(Loader loader) {
     if (cachedCompileTimeError != null) return cachedCompileTimeError;
     return cachedCompileTimeError = loader.coreLibrary
         .getConstructor("_CompileTimeError", bypassLibraryPrivacy: true);
@@ -105,7 +105,7 @@
   /// Returns a reference to the constructor used for creating a runtime error
   /// when a final field is initialized twice. The constructor is expected to
   /// accept a single argument which is the name of the field.
-  Builder getDuplicatedFieldInitializerError(Loader loader) {
+  MemberBuilder getDuplicatedFieldInitializerError(Loader loader) {
     if (cachedDuplicatedFieldInitializerError != null) {
       return cachedDuplicatedFieldInitializerError;
     }
@@ -117,7 +117,7 @@
   /// Returns a reference to the constructor used for creating `native`
   /// annotations. The constructor is expected to accept a single argument of
   /// type String, which is the name of the native method.
-  Builder getNativeAnnotation(Loader loader) {
+  MemberBuilder getNativeAnnotation(Loader loader) {
     if (cachedNativeAnnotation != null) return cachedNativeAnnotation;
     LibraryBuilder internal = loader.read(Uri.parse("dart:_internal"), -1,
         accessor: loader.coreLibrary);
@@ -156,9 +156,6 @@
 
   Severity fixSeverity(Severity severity, Message message, Uri fileUri) {
     severity ??= message.code.severity;
-    if (severity == Severity.errorLegacyWarning) {
-      severity = Severity.error;
-    }
     return rewriteSeverity(severity, message.code, fileUri);
   }
 
diff --git a/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart b/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
index 3f1988c..d8a1daa 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/inference_helper.dart
@@ -10,15 +10,11 @@
 
 import '../fasta_codes.dart' show LocatedMessage, Message;
 
-import '../kernel/forest.dart';
-
 abstract class InferenceHelper {
   CoreTypes get coreTypes;
 
   Uri get uri;
 
-  Forest get forest;
-
   set transformSetLiterals(bool value);
 
   Expression buildProblem(Message message, int charOffset, int length,
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 aca7253..f58a296 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
@@ -24,8 +24,12 @@
 
 import '../../base/instrumentation.dart' show Instrumentation;
 
+import '../builder/library_builder.dart';
+
+import '../kernel/forest.dart';
+
 import '../kernel/kernel_builder.dart'
-    show ClassHierarchyBuilder, ImplicitFieldType, LibraryBuilder;
+    show ClassHierarchyBuilder, ImplicitFieldType;
 
 import '../source/source_library_builder.dart' show SourceLibraryBuilder;
 
@@ -116,6 +120,9 @@
 
   CoreTypes coreTypes;
 
+  // TODO(johnniwinther): Shared this with the BodyBuilder.
+  final Forest forest = const Forest();
+
   /// Indicates whether the "prepare" phase of type inference is complete.
   bool isTypeInferencePrepared = false;
 
@@ -198,10 +205,10 @@
     if (member is Field) {
       DartType type = member.type;
       if (type is ImplicitFieldType) {
-        if (type.member.target != member) {
-          type.member.inferCopiedType(member);
+        if (type.memberBuilder.member != member) {
+          type.memberBuilder.inferCopiedType(member);
         } else {
-          type.member.inferType();
+          type.memberBuilder.inferType();
         }
       }
     }
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 e51fb8d..35f613a 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
@@ -423,7 +423,7 @@
 
   /// The URI of the code for which type inference is currently being
   /// performed--this is used for testing.
-  Uri get uri;
+  Uri get uriForInstrumentation;
 
   /// Performs full type inference on the given field initializer.
   void inferFieldInitializer(
@@ -463,7 +463,7 @@
   final TypeInferenceEngine engine;
 
   @override
-  final Uri uri;
+  final Uri uriForInstrumentation;
 
   /// Indicates whether the construct we are currently performing inference for
   /// is outside of a method body, and hence top level type inference rules
@@ -495,8 +495,8 @@
   /// if the last invocation didn't require any inference.
   FunctionType lastCalleeType;
 
-  TypeInferrerImpl.private(
-      this.engine, this.uri, bool topLevel, this.thisType, this.library)
+  TypeInferrerImpl.private(this.engine, this.uriForInstrumentation,
+      bool topLevel, this.thisType, this.library)
       : assert(library != null),
         classHierarchy = engine.classHierarchy,
         instrumentation = topLevel ? null : engine.instrumentation,
@@ -736,7 +736,7 @@
     if (instrumented &&
         receiverType != const DynamicType() &&
         target.isInstanceMember) {
-      instrumentation?.record(uri, fileOffset, 'target',
+      instrumentation?.record(uriForInstrumentation, fileOffset, 'target',
           new InstrumentationValueForMember(target.member));
     }
 
@@ -770,9 +770,9 @@
       List<ExtensionAccessCandidate> noneMoreSpecific = [];
       library.scope.forEachExtension((ExtensionBuilder extensionBuilder) {
         MemberBuilder thisBuilder =
-            extensionBuilder.lookupLocalMember(name.name, setter: setter);
+            extensionBuilder.lookupLocalMemberByName(name, setter: setter);
         MemberBuilder otherBuilder = extensionBuilder
-            .lookupLocalMember(otherName.name, setter: otherIsSetter);
+            .lookupLocalMemberByName(otherName, setter: otherIsSetter);
         if ((thisBuilder != null && !thisBuilder.isStatic) ||
             (otherBuilder != null && !otherBuilder.isStatic)) {
           DartType onType;
@@ -816,7 +816,9 @@
             ExtensionAccessCandidate candidate = new ExtensionAccessCandidate(
                 onType,
                 onTypeInstantiateToBounds,
-                thisBuilder != null
+                thisBuilder != null &&
+                        !thisBuilder.isField &&
+                        !thisBuilder.isStatic
                     ? new ObjectAccessTarget.extensionMember(
                         thisBuilder.procedure,
                         thisBuilder.extensionTearOff,
@@ -948,7 +950,10 @@
             }
           }
           if (instrumented && instrumentation != null) {
-            instrumentation.record(uri, methodInvocation.fileOffset, 'target',
+            instrumentation.record(
+                uriForInstrumentation,
+                methodInvocation.fileOffset,
+                'target',
                 new InstrumentationValueForMember(interfaceMember));
           }
         }
@@ -966,7 +971,7 @@
       return interfaceTarget;
     } else {
       throw unhandled("${methodInvocation.runtimeType}",
-          "findMethodInvocationMember", methodInvocation.fileOffset, uri);
+          "findMethodInvocationMember", null, null);
     }
   }
 
@@ -989,8 +994,8 @@
         if (instrumented &&
             instrumentation != null &&
             receiverType == const DynamicType()) {
-          instrumentation.record(uri, propertyGet.fileOffset, 'target',
-              new InstrumentationValueForMember(readTarget.member));
+          instrumentation.record(uriForInstrumentation, propertyGet.fileOffset,
+              'target', new InstrumentationValueForMember(readTarget.member));
         }
         propertyGet.interfaceTarget = readTarget.member;
       }
@@ -1005,8 +1010,8 @@
       }
       return interfaceMember;
     } else {
-      return unhandled("${propertyGet.runtimeType}", "findPropertyGetMember",
-          propertyGet.fileOffset, uri);
+      return unhandled(
+          "${propertyGet.runtimeType}", "findPropertyGetMember", null, null);
     }
   }
 
@@ -1029,8 +1034,8 @@
         if (instrumented &&
             instrumentation != null &&
             receiverType == const DynamicType()) {
-          instrumentation.record(uri, propertySet.fileOffset, 'target',
-              new InstrumentationValueForMember(writeTarget.member));
+          instrumentation.record(uriForInstrumentation, propertySet.fileOffset,
+              'target', new InstrumentationValueForMember(writeTarget.member));
         }
         propertySet.interfaceTarget = writeTarget.member;
       }
@@ -1045,8 +1050,8 @@
       }
       return interfaceMember;
     } else {
-      throw unhandled("${propertySet.runtimeType}", "findPropertySetMember",
-          propertySet.fileOffset, uri);
+      throw unhandled(
+          "${propertySet.runtimeType}", "findPropertySetMember", null, null);
     }
   }
 
@@ -1111,7 +1116,8 @@
     throw unhandled('$target', 'getGetterType', null, null);
   }
 
-  /// Returns the getter type of [member] on a receiver of type [receiverType].
+  /// Returns the getter type of [interfaceMember] on a receiver of type
+  /// [receiverType].
   ///
   /// For instance
   ///
@@ -1517,7 +1523,7 @@
           int offset = arguments.fileOffset == -1
               ? expression.fileOffset
               : arguments.fileOffset;
-          instrumentation.record(uri, offset, 'checkReturn',
+          instrumentation.record(uriForInstrumentation, offset, 'checkReturn',
               new InstrumentationValueForType(inferredType));
         }
         return replacement;
@@ -1535,7 +1541,10 @@
           int offset = arguments.fileOffset == -1
               ? expression.fileOffset
               : arguments.fileOffset;
-          instrumentation.record(uri, offset, 'checkGetterReturn',
+          instrumentation.record(
+              uriForInstrumentation,
+              offset,
+              'checkGetterReturn',
               new InstrumentationValueForType(functionType));
         }
         return replacement;
@@ -1580,8 +1589,8 @@
       parent.replaceChild(expressionToReplace, replacedExpression);
     }
     if (instrumentation != null && checkReturn) {
-      instrumentation.record(uri, expression.fileOffset, 'checkReturn',
-          new InstrumentationValueForType(inferredType));
+      instrumentation.record(uriForInstrumentation, expression.fileOffset,
+          'checkReturn', new InstrumentationValueForType(inferredType));
     }
     return replacedExpression;
   }
@@ -1695,7 +1704,7 @@
         typeParameters: calleeType.typeParameters
             .take(extensionTypeParameterCount)
             .toList());
-    Arguments extensionArguments = helper.forest.createArguments(
+    Arguments extensionArguments = engine.forest.createArguments(
         arguments.fileOffset, [arguments.positional.first],
         types: getExplicitExtensionTypeArguments(arguments));
     _inferInvocation(
@@ -1718,7 +1727,7 @@
         typeParameters: targetTypeParameters);
     targetFunctionType =
         extensionSubstitution.substituteType(targetFunctionType);
-    Arguments targetArguments = helper.forest.createArguments(
+    Arguments targetArguments = engine.forest.createArguments(
         arguments.fileOffset, arguments.positional.skip(1).toList(),
         named: arguments.named, types: getExplicitTypeArguments(arguments));
     DartType inferredType = _inferInvocation(
@@ -1898,9 +1907,11 @@
           actualTypes,
           typeContext,
           inferredTypes);
+      assert(inferredTypes.every((type) => isKnown(type)),
+          "Unknown type(s) in inferred types: $inferredTypes.");
       substitution =
           Substitution.fromPairs(calleeTypeParameters, inferredTypes);
-      instrumentation?.record(uri, offset, 'typeArgs',
+      instrumentation?.record(uriForInstrumentation, offset, 'typeArgs',
           new InstrumentationValueForTypeArgs(inferredTypes));
       arguments.types.clear();
       arguments.types.addAll(inferredTypes);
@@ -2046,8 +2057,8 @@
         } else {
           inferredType = const DynamicType();
         }
-        instrumentation?.record(uri, formal.fileOffset, 'type',
-            new InstrumentationValueForType(inferredType));
+        instrumentation?.record(uriForInstrumentation, formal.fileOffset,
+            'type', new InstrumentationValueForType(inferredType));
         formal.type = inferredType;
       }
     }
@@ -2082,7 +2093,7 @@
     // type `<T0, ..., Tn>(R0, ..., Rn) -> M’` (with some of the `Ri` and `xi`
     // denoted as optional or named parameters, if appropriate).
     if (needToSetReturnType) {
-      instrumentation?.record(uri, fileOffset, 'returnType',
+      instrumentation?.record(uriForInstrumentation, fileOffset, 'returnType',
           new InstrumentationValueForType(inferredReturnType));
       function.returnType = inferredReturnType;
     }
@@ -2123,10 +2134,10 @@
     Expression replacement;
     expression.parent.replaceChild(
         expression,
-        replacement = helper.forest.createStaticInvocation(
+        replacement = engine.forest.createStaticInvocation(
             expression.fileOffset,
             target.member,
-            arguments = helper.forest.createArgumentsForExtensionMethod(
+            arguments = engine.forest.createArgumentsForExtensionMethod(
                 arguments.fileOffset,
                 target.inferredExtensionTypeArguments.length,
                 procedure.function.typeParameters.length -
@@ -2198,9 +2209,9 @@
         parent?.replaceChild(node, errorNode);
       }
     }
-    if (target.isExtensionMember) {
-      library.checkBoundsInStaticInvocation(
-          replacement, typeSchemaEnvironment, helper.uri);
+    if (!isTopLevel && target.isExtensionMember) {
+      library.checkBoundsInStaticInvocation(replacement, typeSchemaEnvironment,
+          helper.uri, getTypeArgumentsInfo(node.arguments));
     } else {
       _checkBoundsInMethodInvocation(target, receiverType, calleeType,
           methodName, arguments, node.fileOffset);
@@ -2249,8 +2260,7 @@
           interfaceTarget,
           arguments,
           helper.uri,
-          fileOffset,
-          inferred: getExplicitTypeArguments(arguments) == null);
+          fileOffset);
     }
   }
 
@@ -2345,8 +2355,8 @@
         includeExtensionMethods: true);
     if (readTarget.isInstanceMember) {
       if (instrumentation != null && receiverType == const DynamicType()) {
-        instrumentation.record(uri, propertyGet.fileOffset, 'target',
-            new InstrumentationValueForMember(readTarget.member));
+        instrumentation.record(uriForInstrumentation, propertyGet.fileOffset,
+            'target', new InstrumentationValueForMember(readTarget.member));
       }
       propertyGet.interfaceTarget = readTarget.member;
     }
@@ -2366,10 +2376,10 @@
         case ProcedureKind.Getter:
           expression.parent.replaceChild(
               expression,
-              replacement = expression = helper.forest.createStaticInvocation(
+              replacement = expression = engine.forest.createStaticInvocation(
                   fileOffset,
                   readTarget.member,
-                  helper.forest.createArgumentsForExtensionMethod(
+                  engine.forest.createArgumentsForExtensionMethod(
                       fileOffset,
                       readTarget.inferredExtensionTypeArguments.length,
                       0,
@@ -2380,10 +2390,10 @@
         case ProcedureKind.Method:
           expression.parent.replaceChild(
               expression,
-              replacement = expression = helper.forest.createStaticInvocation(
+              replacement = expression = engine.forest.createStaticInvocation(
                   fileOffset,
                   readTarget.tearoffTarget,
-                  helper.forest.createArgumentsForExtensionMethod(
+                  engine.forest.createArgumentsForExtensionMethod(
                       fileOffset,
                       readTarget.inferredExtensionTypeArguments.length,
                       0,
@@ -2396,7 +2406,7 @@
         case ProcedureKind.Setter:
         case ProcedureKind.Factory:
         case ProcedureKind.Operator:
-          unhandled('$readTarget', "inferPropertyGet", fileOffset, uri);
+          unhandled('$readTarget', "inferPropertyGet", null, null);
           break;
       }
     }
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 6a2aa4e..9399c64 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
@@ -99,6 +99,9 @@
     for (NamedType namedParameterType in node.namedParameters) {
       if (!namedParameterType.type.accept(this)) return false;
     }
+    if (node.typedefType != null && !node.typedefType.accept(this)) {
+      return false;
+    }
     return true;
   }
 
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 e7fc374..00f3516 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
@@ -2,14 +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.md file.
 
-import 'package:kernel/ast.dart'
-    show
-        DartType,
-        DartTypeVisitor,
-        DynamicType,
-        FunctionType,
-        InterfaceType,
-        NamedType;
+import 'package:kernel/ast.dart' hide MapEntry;
 
 import 'package:kernel/core_types.dart' show CoreTypes;
 
@@ -52,7 +45,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 extends DartTypeVisitor<DartType> {
+class _TypeSchemaEliminationVisitor implements DartTypeVisitor<DartType> {
   final DartType nullType;
 
   bool isLeastClosure;
@@ -98,7 +91,8 @@
           namedParameters: newNamedParameters ?? node.namedParameters,
           typeParameters: node.typeParameters,
           requiredParameterCount: node.requiredParameterCount,
-          typedefType: typedefType);
+          typedefType: typedefType,
+          nullability: node.nullability);
     }
   }
 
@@ -116,7 +110,51 @@
       // No type arguments needed to be substituted.
       return null;
     } else {
-      return new InterfaceType(node.classNode, newTypeArguments);
+      return new InterfaceType(
+          node.classNode, newTypeArguments, node.nullability);
+    }
+  }
+
+  @override
+  DartType visitDynamicType(DynamicType 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, newPromotedBound,
+            node.typeParameterTypeNullability);
+      }
+    }
+    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, newTypeArguments, node.nullability);
     }
   }
 
diff --git a/pkg/front_end/lib/src/scanner/token.dart b/pkg/front_end/lib/src/scanner/token.dart
index 37a8a52..b74e169 100644
--- a/pkg/front_end/lib/src/scanner/token.dart
+++ b/pkg/front_end/lib/src/scanner/token.dart
@@ -217,7 +217,8 @@
   static const Keyword IS =
       const Keyword("is", "IS", precedence: RELATIONAL_PRECEDENCE);
 
-  static const Keyword LATE = const Keyword("late", "LATE", isModifier: true);
+  static const Keyword LATE =
+      const Keyword("late", "LATE", isModifier: true, isBuiltIn: true);
 
   static const Keyword LIBRARY = const Keyword("library", "LIBRARY",
       isBuiltIn: true, isTopLevelKeyword: true);
diff --git a/pkg/front_end/lib/src/testing/id_testing.dart b/pkg/front_end/lib/src/testing/id_testing.dart
index 3c49ea0..5b001ac 100644
--- a/pkg/front_end/lib/src/testing/id_testing.dart
+++ b/pkg/front_end/lib/src/testing/id_testing.dart
@@ -8,6 +8,7 @@
 import '../fasta/colors.dart' as colors;
 
 const String cfeMarker = 'cfe';
+const String cfeWithNnbdMarker = '$cfeMarker:nnbd';
 const String dart2jsMarker = 'dart2js';
 const String analyzerMarker = 'analyzer';
 
@@ -18,6 +19,14 @@
   analyzerMarker,
 ];
 
+/// Markers used in annotated tests shard by CFE, analyzer and dart2js.
+const List<String> sharedMarkersWithNnbd = [
+  cfeMarker,
+  cfeWithNnbdMarker,
+  dart2jsMarker,
+  analyzerMarker,
+];
+
 /// `true` if ANSI colors are supported by stdout.
 bool useColors = stdout.supportsAnsiEscapes;
 
diff --git a/pkg/front_end/lib/src/testing/id_testing_helper.dart b/pkg/front_end/lib/src/testing/id_testing_helper.dart
index 68aa64d..b6b91be 100644
--- a/pkg/front_end/lib/src/testing/id_testing_helper.dart
+++ b/pkg/front_end/lib/src/testing/id_testing_helper.dart
@@ -24,6 +24,7 @@
         RunTestFunction,
         TestData,
         cfeMarker,
+        cfeWithNnbdMarker,
         checkCode;
 import 'id_testing_utils.dart';
 
@@ -34,10 +35,10 @@
 /// Test configuration used for testing CFE in its default state.
 const TestConfig defaultCfeConfig = const TestConfig(cfeMarker, 'cfe');
 
-/// Test configuration used for testing CFE with extension methods.
-const TestConfig cfeExtensionMethodsConfig = const TestConfig(
-    cfeMarker, 'cfe with extension methods',
-    experimentalFlags: const {ExperimentalFlag.extensionMethods: true});
+/// Test configuration used for testing CFE with nnbd.
+const TestConfig cfeNonNullableConfig = const TestConfig(
+    cfeWithNnbdMarker, 'cfe with nnbd',
+    experimentalFlags: const {ExperimentalFlag.nonNullable: true});
 
 class TestConfig {
   final String marker;
diff --git a/pkg/front_end/lib/src/testing/id_testing_utils.dart b/pkg/front_end/lib/src/testing/id_testing_utils.dart
index 0c98653..2c5d963 100644
--- a/pkg/front_end/lib/src/testing/id_testing_utils.dart
+++ b/pkg/front_end/lib/src/testing/id_testing_utils.dart
@@ -3,9 +3,14 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:kernel/ast.dart';
-import '../fasta/builder/builder.dart';
+
+import '../fasta/builder/class_builder.dart';
+import '../fasta/builder/library_builder.dart';
+import '../fasta/builder/member_builder.dart';
+import '../fasta/builder/named_type_builder.dart';
+import '../fasta/builder/type_builder.dart';
+import '../fasta/builder/type_variable_builder.dart';
 import '../fasta/builder/extension_builder.dart';
-import '../fasta/kernel/kernel_builder.dart';
 import '../fasta/messages.dart';
 import '../fasta/source/source_library_builder.dart';
 import '../fasta/source/source_loader.dart';
@@ -412,6 +417,9 @@
       visitList(node.typeArguments);
       sb.write('>');
     }
+    if (!isNull(node)) {
+      sb.write(nullabilityToText(node.nullability));
+    }
   }
 
   void visitFunctionType(FunctionType node) {
@@ -441,12 +449,15 @@
       }
       sb.write('}');
     }
-    sb.write(')->');
+    sb.write(')');
+    sb.write(nullabilityToText(node.nullability));
+    sb.write('->');
     visit(node.returnType);
   }
 
   void visitTypeParameterType(TypeParameterType node) {
     sb.write(node.parameter.name);
+    sb.write(nullabilityToText(node.nullability));
     if (node.promotedBound != null) {
       sb.write(' extends ');
       visit(node.promotedBound);
@@ -460,6 +471,7 @@
       visitList(node.typeArguments);
       sb.write('>');
     }
+    sb.write(nullabilityToText(node.nullability));
   }
 }
 
@@ -470,6 +482,13 @@
       '${type.classNode.enclosingLibrary.importUri}' == 'dart:core';
 }
 
+/// Returns `true` if [type] is `Null` from `dart:core`.
+bool isNull(DartType type) {
+  return type is InterfaceType &&
+      type.classNode.name == 'Null' &&
+      '${type.classNode.enclosingLibrary.importUri}' == 'dart:core';
+}
+
 /// Returns a textual representation of the [typeParameter] to be used in
 /// testing.
 String typeParameterToText(TypeParameter typeParameter) {
@@ -560,3 +579,18 @@
   }
   return sb.toString();
 }
+
+/// Returns a textual representation of [nullability] to be used in testing.
+String nullabilityToText(Nullability nullability) {
+  switch (nullability) {
+    case Nullability.nonNullable:
+      return '!';
+    case Nullability.nullable:
+      return '?';
+    case Nullability.neither:
+      return '%';
+    case Nullability.legacy:
+      return '';
+  }
+  throw new UnsupportedError('Unexpected nullability: $nullability.');
+}
diff --git a/pkg/front_end/messages.status b/pkg/front_end/messages.status
index ccc99a2..de43c6a 100644
--- a/pkg/front_end/messages.status
+++ b/pkg/front_end/messages.status
@@ -69,7 +69,6 @@
 ConstConstructorInSubclassOfMixinApplication/example: Fail
 ConstConstructorNonFinalField/example: Fail
 ConstConstructorRedirectionToNonConst/analyzerCode: Fail # The analyzer doesn't report this error.
-ConstConstructorWithNonConstSuper/example: Fail
 ConstEvalCircularity/example: Fail
 ConstEvalContext/analyzerCode: Fail # This is just used for displaying the context.
 ConstEvalContext/example: Fail # This is just used for displaying the context.
@@ -264,11 +263,9 @@
 FfiStructAnnotation/analyzerCode: Fail
 FfiTypeInvalid/analyzerCode: Fail
 FfiTypeMismatch/analyzerCode: Fail
-FfiTypeUnsized/analyzerCode: Fail
 FfiDartTypeMismatch/analyzerCode: Fail
 FfiExtendsOrImplementsSealedClass/analyzerCode: Fail
 FfiStructGeneric/analyzerCode: Fail
-FfiWrongStructInheritance/analyzerCode: Fail
 FfiExpectedExceptionalReturn/analyzerCode: Fail
 FfiExpectedNoExceptionalReturn/analyzerCode: Fail
 FfiExpectedConstant/analyzerCode: Fail
diff --git a/pkg/front_end/messages.yaml b/pkg/front_end/messages.yaml
index e67853d..290619a 100644
--- a/pkg/front_end/messages.yaml
+++ b/pkg/front_end/messages.yaml
@@ -738,10 +738,6 @@
   script:
     - "class C { int x; C.bad() : super(), x = 5; }"
 
-ConstConstructorWithNonConstSuper:
-  template: "Constant constructor can't call non-constant super constructors."
-  analyzerCode: CONST_CONSTRUCTOR_WITH_NON_CONST_SUPER
-
 ExtraneousModifier:
   index: 77
   template: "Can't have modifier '#lexeme' here."
@@ -775,6 +771,14 @@
     - "abstract typedef foo();"
     - "static typedef foo();"
 
+ExtraneousModifierInExtension:
+  index: 98
+  template: "Can't have modifier '#lexeme' in an extension."
+  tip: "Try removing '#lexeme'."
+  analyzerCode: ParserErrorCode.INVALID_USE_OF_COVARIANT_IN_EXTENSION
+  script:
+    - "extension on String { foo(covariant String child) {} }"
+
 FinalAndCovariant:
   index: 80
   template: "Members can't be declared to be both 'final' and 'covariant'."
@@ -1279,7 +1283,6 @@
 
 ConstructorNotFound:
   template: "Couldn't find constructor '#name'."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: CONSTRUCTOR_NOT_FOUND
 
 ConstructorWithReturnType:
@@ -1336,7 +1339,6 @@
 
 RedirectionTargetNotFound:
   template: "Redirection constructor target not found: '#name'"
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: REDIRECT_TO_MISSING_CONSTRUCTOR
 
 CyclicTypedef:
@@ -1345,28 +1347,23 @@
 
 TypeNotFound:
   template: "Type '#name' not found."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: UNDEFINED_CLASS
 
 NonInstanceTypeVariableUse:
   template: "Can only use type variables in instance methods."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: TYPE_PARAMETER_REFERENCED_BY_STATIC
 
 GetterNotFound:
   template: "Getter not found: '#name'."
   analyzerCode: UNDEFINED_GETTER
-  severity: ERROR_LEGACY_WARNING
 
 SetterNotFound:
   template: "Setter not found: '#name'."
   analyzerCode: UNDEFINED_SETTER
-  severity: ERROR_LEGACY_WARNING
 
 MethodNotFound:
   template: "Method not found: '#name'."
   analyzerCode: UNDEFINED_METHOD
-  severity: ERROR_LEGACY_WARNING
 
 CandidateFound:
   template: "Found this candidate, but the arguments don't match."
@@ -1381,23 +1378,19 @@
 
 TooFewArguments:
   template: "Too few positional arguments: #count required, #count2 given."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: NOT_ENOUGH_REQUIRED_ARGUMENTS
 
 TooManyArguments:
   template: "Too many positional arguments: #count allowed, but #count2 found."
   tip: "Try removing the extra positional arguments."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: EXTRA_POSITIONAL_ARGUMENTS
 
 NoSuchNamedParameter:
   template: "No named parameter with the name '#name'."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: UNDEFINED_NAMED_PARAMETER
 
 AbstractClassInstantiation:
   template: "The class '#name' is abstract and can't be instantiated."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: NEW_WITH_ABSTRACT_CLASS
 
 EnumInstantiation:
@@ -1406,7 +1399,6 @@
 
 AbstractRedirectedClassInstantiation:
   template: "Factory redirects to class '#name', which is abstract and can't be instantiated."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: FACTORY_REDIRECTS_TO_ABSTRACT_CLASS
 
 MissingImplementationNotAbstract:
@@ -1438,25 +1430,20 @@
 
 ListLiteralTooManyTypeArguments:
   template: "List literal requires exactly one type argument."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: EXPECTED_ONE_LIST_TYPE_ARGUMENTS
 
 SetLiteralTooManyTypeArguments:
   template: "A set literal requires exactly one type argument."
-  severity: ERROR_LEGACY_WARNING
 
 MapLiteralTypeArgumentMismatch:
   template: "A map literal requires exactly two type arguments."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: EXPECTED_TWO_MAP_TYPE_ARGUMENTS
 
 SetOrMapLiteralTooManyTypeArguments:
   template: "A set or map literal requires exactly one or two type arguments, respectively."
-  severity: ERROR_LEGACY_WARNING
 
 LoadLibraryTakesNoArguments:
   template: "'loadLibrary' takes no arguments."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: LOAD_LIBRARY_TAKES_NO_ARGUMENTS
 
 LoadLibraryHidesMember:
@@ -1466,12 +1453,10 @@
 
 TypeArgumentMismatch:
   template: "Expected #count type arguments."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: WRONG_NUMBER_OF_TYPE_ARGUMENTS
 
 NotAType:
   template: "'#name' isn't a type."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: NOT_A_TYPE
 
 NotATypeContext:
@@ -1480,7 +1465,6 @@
 
 NotAPrefixInTypeAnnotation:
   template: "'#name.#name2' can't be used as a type because '#name' doesn't refer to an import prefix."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: NOT_A_TYPE
   declaration:
     - |
@@ -1494,7 +1478,6 @@
 
 UnresolvedPrefixInTypeAnnotation:
   template: "'#name.#name2' can't be used as a type because '#name' isn't defined."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: NOT_A_TYPE
   statement: "T.String x;"
 
@@ -1589,6 +1572,12 @@
         internal stack trace from the compiler. Multiple kinds can be separated by
         commas, for example, --fatal=errors,warnings.
 
+      --fatal-skip=<number>
+      --fatal-skip=trace
+        Skip this many messages that would otherwise be fatal before aborting the
+        compilation. Default is 0, which stops at the first message. Specify
+        'trace' to print a stack trace for every message without stopping.
+
       --enable-experiment=<flag>
         Enable or disable an experimental flag, used to guard features currently
         in development. Prefix an experiment name with 'no-' to disable it.
@@ -1609,7 +1598,6 @@
 
 ReturnTypeFunctionExpression:
   template: "A function expression can't have a return type."
-  severity: ERROR_LEGACY_WARNING
 
 InternalProblemUnhandled:
   template: "Unhandled #string in #string2."
@@ -1706,6 +1694,10 @@
   template: "Local definition of '#name' hides import from '#uri'."
   severity: IGNORED
 
+DebugTrace:
+  template: "Fatal '#name' at:\n#string"
+  severity: IGNORED
+
 ExportHidesExport:
   template: "Export of '#name' (from '#uri') hides export from '#uri2'."
   severity: IGNORED
@@ -1735,7 +1727,6 @@
 DeferredTypeAnnotation:
   template: "The type '#type' is deferred loaded via prefix '#name' and can't be used as a type annotation."
   tip: "Try removing 'deferred' from the import of '#name' or use a supertype of '#type' that isn't deferred."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: TYPE_ANNOTATION_DEFERRED_CLASS
 
 DuplicatePrefix:
@@ -1772,7 +1763,6 @@
 
 DuplicatedExportInType:
   template: "'#name' is exported from both '#uri' and '#uri2'."
-  severity: ERROR_LEGACY_WARNING
 
 DuplicatedImport:
   template: "'#name' is imported from both '#uri' and '#uri2'."
@@ -1793,7 +1783,6 @@
 
 DuplicatedImportInType:
   template: "'#name' is imported from both '#uri' and '#uri2'."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: AMBIGUOUS_IMPORT
   script:
     lib1.dart: "class A {}"
@@ -1913,20 +1902,10 @@
   template: "Conflicts with member '#name'."
   analyzerCode: CONFLICTS_WITH_MEMBER
 
-ConflictsWithMemberWarning:
-  template: "Conflicts with member '#name'."
-  severity: ERROR_LEGACY_WARNING
-  analyzerCode: CONFLICTS_WITH_MEMBER
-
 ConflictsWithSetter:
   template: "Conflicts with setter '#name'."
   analyzerCode: CONFLICTS_WITH_MEMBER
 
-ConflictsWithSetterWarning:
-  template: "Conflicts with setter '#name'."
-  severity: ERROR_LEGACY_WARNING
-  analyzerCode: CONFLICTS_WITH_MEMBER
-
 ConflictsWithTypeVariable:
   template: "Conflicts with type variable '#name'."
   analyzerCode: CONFLICTING_TYPE_VARIABLE_AND_MEMBER
@@ -2022,7 +2001,6 @@
 
 OverrideTypeVariablesMismatch:
   template: "Declared type variables of '#name' doesn't match those on overridden method '#name2'."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: INVALID_METHOD_OVERRIDE_TYPE_PARAMETERS
 
 OverriddenMethodCause:
@@ -2031,22 +2009,18 @@
 
 OverrideMismatchNamedParameter:
   template: "The method '#name' doesn't have the named parameter '#name2' of overridden method '#name3'."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: INVALID_OVERRIDE_NAMED
 
 OverrideFewerNamedArguments:
   template: "The method '#name' has fewer named arguments than those of overridden method '#name2'."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: INVALID_OVERRIDE_NAMED
 
 OverrideFewerPositionalArguments:
   template: "The method '#name' has fewer positional arguments than those of overridden method '#name2'."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: INVALID_OVERRIDE_POSITIONAL
 
 OverrideMoreRequiredArguments:
   template: "The method '#name' has more required arguments than those of overridden method '#name2'."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: INVALID_OVERRIDE_REQUIRED
 
 OverrideTypeMismatchParameter:
@@ -2355,7 +2329,6 @@
   index: 13
   template: "Can't use type arguments with type variable '#name'."
   tip: "Try removing the type arguments."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: ParserErrorCode.TYPE_ARGUMENTS_ON_TYPE_VARIABLE
   script:
     - "dynamic<T>(x) => 0"
@@ -2501,18 +2474,15 @@
 PartOfLibraryNameMismatch:
   template: "Using '#uri' as part of '#name' but its 'part of' declaration says '#name2'."
   analyzerCode: PART_OF_DIFFERENT_LIBRARY
-  severity: ERROR_LEGACY_WARNING
 
 PartOfUseUri:
   template: "Using '#uri' as part of '#uri2' but its 'part of' declaration says '#name'."
   tip: "Try changing the 'part of' declaration to use a relative file name."
   analyzerCode: PART_OF_UNNAMED_LIBRARY
-  severity: ERROR_LEGACY_WARNING
 
 PartOfUriMismatch:
   template: "Using '#uri' as part of '#uri2' but its 'part of' declaration says '#uri3'."
   analyzerCode: PART_OF_DIFFERENT_LIBRARY
-  severity: ERROR_LEGACY_WARNING
 
 MissingMain:
   template: "No 'main' method found."
@@ -2599,7 +2569,6 @@
 
 SwitchCaseFallThrough:
   template: "Switch case may fall through to the next case."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: CASE_BLOCK_NOT_TERMINATED
 
 FinalInstanceVariableAlreadyInitialized:
@@ -2607,7 +2576,6 @@
   # TODO(ahe): Strictly speaking, as of
   # 3b5874a332b24f326775b3520f32b9a818731aca, this is a compile-time error in
   # legacy mode.
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: FINAL_INITIALIZED_MULTIPLE_TIMES
 
 FinalInstanceVariableAlreadyInitializedCause:
@@ -2616,7 +2584,6 @@
 
 TypeVariableInStaticContext:
   template: "Type variables can't be used in static members."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: TYPE_PARAMETER_REFERENCED_BY_STATIC
   declaration:
     - |
@@ -2675,26 +2642,21 @@
 
 SuperclassMethodArgumentMismatch:
   template: "Superclass doesn't have a method named '#name' with matching arguments."
-  severity: ERROR_LEGACY_WARNING
 
 SuperclassHasNoGetter:
   template: "Superclass has no getter named '#name'."
   analyzerCode: UNDEFINED_SUPER_GETTER
-  severity: ERROR_LEGACY_WARNING
 
 SuperclassHasNoSetter:
   template: "Superclass has no setter named '#name'."
   analyzerCode: UNDEFINED_SUPER_SETTER
-  severity: ERROR_LEGACY_WARNING
 
 SuperclassHasNoMethod:
   template: "Superclass has no method named '#name'."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: UNDEFINED_SUPER_METHOD
 
 SuperclassHasNoConstructor:
   template: "Superclass has no constructor named '#name'."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode:
     - UNDEFINED_CONSTRUCTOR_IN_INITIALIZER
     - UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT
@@ -2737,6 +2699,18 @@
         A.bar() {}
       }
 
+ConstConstructorWithNonConstSuper:
+  template: "A constant constructor can't call a non-constant super constructor."
+  analyzerCode: CONST_CONSTRUCTOR_WITH_NON_CONST_SUPER
+  script:
+    - >-
+      class A {
+        A.bar() {}
+      }
+      class B extends A {
+        const B.foo() : super.bar();
+      }
+
 AccessError:
   template: "Access error: '#name'."
 
@@ -3030,7 +3004,6 @@
 InitializingFormalTypeMismatch:
   template: "The type of parameter '#name', '#type' is not a subtype of the corresponding field's type, '#type2'."
   tip: "Try changing the type of parameter '#name' to a subtype of '#type2'."
-  severity: ERROR_LEGACY_WARNING
   analyzerCode: INVALID_PARAMETER_DECLARATION
   script: >
     class C {
@@ -3502,11 +3475,6 @@
   template: "Expected type '#type' to be a valid and instantiated subtype of 'NativeType'."
   external: test/ffi_test.dart
 
-FfiTypeUnsized:
-  # Used by dart:ffi
-  template: "Method '#name' cannot be called on something of type '#type' as this type is unsized."
-  external: test/ffi_test.dart
-
 FfiFieldAnnotation:
   # Used by dart:ffi
   template: "Field '#name' requires exactly one annotation to declare its native type, which cannot be Void. dart:ffi Structs cannot have regular Dart fields."
@@ -3537,11 +3505,6 @@
   template: "Struct '#name' should not be generic."
   external: test/ffi_test.dart
 
-FfiWrongStructInheritance:
-  # Used by dart:ffi
-  template: "Struct '#name' must inherit from 'Struct<#name>'."
-  external: test/ffi_test.dart
-
 FfiDartTypeMismatch:
   # Used by dart:ffi
   template: "Expected '#type' to be a subtype of '#type2'."
diff --git a/pkg/front_end/parser_testcases/extensions/covariant.dart.expect b/pkg/front_end/parser_testcases/extensions/covariant.dart.expect
index ebb1635..e58a125 100644
--- a/pkg/front_end/parser_testcases/extensions/covariant.dart.expect
+++ b/pkg/front_end/parser_testcases/extensions/covariant.dart.expect
@@ -47,17 +47,18 @@
             handleNoType({)
             handleIdentifier(addChild, methodDeclaration)
             handleNoTypeVariables(()
-            beginFormalParameters((, MemberKind.NonStaticMethod)
+            beginFormalParameters((, MemberKind.ExtensionNonStaticMethod)
               beginMetadataStar(covariant)
               endMetadataStar(0)
-              beginFormalParameter(covariant, MemberKind.NonStaticMethod, null, covariant, null)
+              handleRecoverableError(Message[ExtraneousModifierInExtension, Can't have modifier 'covariant' in an extension., Try removing 'covariant'., {token: covariant}], covariant, covariant)
+              beginFormalParameter(covariant, MemberKind.ExtensionNonStaticMethod, null, null, null)
                 handleIdentifier(A, typeReference)
                 handleNoTypeArguments(child)
                 handleType(A, null)
                 handleIdentifier(child, formalParameterDeclaration)
                 handleFormalParameterWithoutValue())
-              endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
-            endFormalParameters(1, (, ), MemberKind.NonStaticMethod)
+              endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.ExtensionNonStaticMethod)
+            endFormalParameters(1, (, ), MemberKind.ExtensionNonStaticMethod)
             handleNoInitializers()
             handleAsyncModifier(null, null)
             beginBlockFunctionBody({)
diff --git a/pkg/front_end/parser_testcases/extensions/covariant.dart.intertwined.expect b/pkg/front_end/parser_testcases/extensions/covariant.dart.intertwined.expect
index 6cf377f..ed90d20 100644
--- a/pkg/front_end/parser_testcases/extensions/covariant.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/extensions/covariant.dart.intertwined.expect
@@ -89,23 +89,25 @@
               parseQualifiedRestOpt(addChild, methodDeclarationContinuation)
               parseMethodTypeVar(addChild)
                 listener: handleNoTypeVariables(()
-              parseGetterOrFormalParameters(addChild, addChild, false, MemberKind.NonStaticMethod)
-                parseFormalParameters(addChild, MemberKind.NonStaticMethod)
-                  parseFormalParametersRest((, MemberKind.NonStaticMethod)
-                    listener: beginFormalParameters((, MemberKind.NonStaticMethod)
-                    parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
+              parseGetterOrFormalParameters(addChild, addChild, false, MemberKind.ExtensionNonStaticMethod)
+                parseFormalParameters(addChild, MemberKind.ExtensionNonStaticMethod)
+                  parseFormalParametersRest((, MemberKind.ExtensionNonStaticMethod)
+                    listener: beginFormalParameters((, MemberKind.ExtensionNonStaticMethod)
+                    parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.ExtensionNonStaticMethod)
                       parseMetadataStar(()
                         listener: beginMetadataStar(covariant)
                         listener: endMetadataStar(0)
-                      listener: beginFormalParameter(covariant, MemberKind.NonStaticMethod, null, covariant, null)
+                      reportRecoverableErrorWithToken(covariant, Instance of 'Template<(Token) => Message>')
+                        listener: handleRecoverableError(Message[ExtraneousModifierInExtension, Can't have modifier 'covariant' in an extension., Try removing 'covariant'., {token: covariant}], covariant, covariant)
+                      listener: beginFormalParameter(covariant, MemberKind.ExtensionNonStaticMethod, null, null, null)
                       listener: handleIdentifier(A, typeReference)
                       listener: handleNoTypeArguments(child)
                       listener: handleType(A, null)
                       ensureIdentifier(A, formalParameterDeclaration)
                         listener: handleIdentifier(child, formalParameterDeclaration)
                       listener: handleFormalParameterWithoutValue())
-                      listener: endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
-                    listener: endFormalParameters(1, (, ), MemberKind.NonStaticMethod)
+                      listener: endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.ExtensionNonStaticMethod)
+                    listener: endFormalParameters(1, (, ), MemberKind.ExtensionNonStaticMethod)
               parseInitializersOpt())
                 listener: handleNoInitializers()
               parseAsyncModifierOpt())
diff --git a/pkg/front_end/parser_testcases/extensions/not_covariant.dart.expect b/pkg/front_end/parser_testcases/extensions/not_covariant.dart.expect
index b0b1098..53bb150 100644
--- a/pkg/front_end/parser_testcases/extensions/not_covariant.dart.expect
+++ b/pkg/front_end/parser_testcases/extensions/not_covariant.dart.expect
@@ -47,17 +47,17 @@
             handleNoType({)
             handleIdentifier(addChild, methodDeclaration)
             handleNoTypeVariables(()
-            beginFormalParameters((, MemberKind.NonStaticMethod)
+            beginFormalParameters((, MemberKind.ExtensionNonStaticMethod)
               beginMetadataStar(A)
               endMetadataStar(0)
-              beginFormalParameter(A, MemberKind.NonStaticMethod, null, null, null)
+              beginFormalParameter(A, MemberKind.ExtensionNonStaticMethod, null, null, null)
                 handleIdentifier(A, typeReference)
                 handleNoTypeArguments(child)
                 handleType(A, null)
                 handleIdentifier(child, formalParameterDeclaration)
                 handleFormalParameterWithoutValue())
-              endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
-            endFormalParameters(1, (, ), MemberKind.NonStaticMethod)
+              endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.ExtensionNonStaticMethod)
+            endFormalParameters(1, (, ), MemberKind.ExtensionNonStaticMethod)
             handleNoInitializers()
             handleAsyncModifier(null, null)
             beginBlockFunctionBody({)
diff --git a/pkg/front_end/parser_testcases/extensions/not_covariant.dart.intertwined.expect b/pkg/front_end/parser_testcases/extensions/not_covariant.dart.intertwined.expect
index 18aa1ae..498b744 100644
--- a/pkg/front_end/parser_testcases/extensions/not_covariant.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/extensions/not_covariant.dart.intertwined.expect
@@ -89,23 +89,23 @@
               parseQualifiedRestOpt(addChild, methodDeclarationContinuation)
               parseMethodTypeVar(addChild)
                 listener: handleNoTypeVariables(()
-              parseGetterOrFormalParameters(addChild, addChild, false, MemberKind.NonStaticMethod)
-                parseFormalParameters(addChild, MemberKind.NonStaticMethod)
-                  parseFormalParametersRest((, MemberKind.NonStaticMethod)
-                    listener: beginFormalParameters((, MemberKind.NonStaticMethod)
-                    parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
+              parseGetterOrFormalParameters(addChild, addChild, false, MemberKind.ExtensionNonStaticMethod)
+                parseFormalParameters(addChild, MemberKind.ExtensionNonStaticMethod)
+                  parseFormalParametersRest((, MemberKind.ExtensionNonStaticMethod)
+                    listener: beginFormalParameters((, MemberKind.ExtensionNonStaticMethod)
+                    parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.ExtensionNonStaticMethod)
                       parseMetadataStar(()
                         listener: beginMetadataStar(A)
                         listener: endMetadataStar(0)
-                      listener: beginFormalParameter(A, MemberKind.NonStaticMethod, null, null, null)
+                      listener: beginFormalParameter(A, MemberKind.ExtensionNonStaticMethod, null, null, null)
                       listener: handleIdentifier(A, typeReference)
                       listener: handleNoTypeArguments(child)
                       listener: handleType(A, null)
                       ensureIdentifier(A, formalParameterDeclaration)
                         listener: handleIdentifier(child, formalParameterDeclaration)
                       listener: handleFormalParameterWithoutValue())
-                      listener: endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.NonStaticMethod)
-                    listener: endFormalParameters(1, (, ), MemberKind.NonStaticMethod)
+                      listener: endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.ExtensionNonStaticMethod)
+                    listener: endFormalParameters(1, (, ), MemberKind.ExtensionNonStaticMethod)
               parseInitializersOpt())
                 listener: handleNoInitializers()
               parseAsyncModifierOpt())
diff --git a/pkg/front_end/parser_testcases/extensions/static.dart.expect b/pkg/front_end/parser_testcases/extensions/static.dart.expect
index 7b1a576..2552e83 100644
--- a/pkg/front_end/parser_testcases/extensions/static.dart.expect
+++ b/pkg/front_end/parser_testcases/extensions/static.dart.expect
@@ -47,17 +47,17 @@
             handleNoType(static)
             handleIdentifier(addChild, methodDeclaration)
             handleNoTypeVariables(()
-            beginFormalParameters((, MemberKind.StaticMethod)
+            beginFormalParameters((, MemberKind.ExtensionStaticMethod)
               beginMetadataStar(A)
               endMetadataStar(0)
-              beginFormalParameter(A, MemberKind.StaticMethod, null, null, null)
+              beginFormalParameter(A, MemberKind.ExtensionStaticMethod, null, null, null)
                 handleIdentifier(A, typeReference)
                 handleNoTypeArguments(child)
                 handleType(A, null)
                 handleIdentifier(child, formalParameterDeclaration)
                 handleFormalParameterWithoutValue())
-              endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.StaticMethod)
-            endFormalParameters(1, (, ), MemberKind.StaticMethod)
+              endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.ExtensionStaticMethod)
+            endFormalParameters(1, (, ), MemberKind.ExtensionStaticMethod)
             handleNoInitializers()
             handleAsyncModifier(null, null)
             beginBlockFunctionBody({)
diff --git a/pkg/front_end/parser_testcases/extensions/static.dart.intertwined.expect b/pkg/front_end/parser_testcases/extensions/static.dart.intertwined.expect
index 6db427e..836dd78 100644
--- a/pkg/front_end/parser_testcases/extensions/static.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/extensions/static.dart.intertwined.expect
@@ -89,23 +89,23 @@
               parseQualifiedRestOpt(addChild, methodDeclarationContinuation)
               parseMethodTypeVar(addChild)
                 listener: handleNoTypeVariables(()
-              parseGetterOrFormalParameters(addChild, addChild, false, MemberKind.StaticMethod)
-                parseFormalParameters(addChild, MemberKind.StaticMethod)
-                  parseFormalParametersRest((, MemberKind.StaticMethod)
-                    listener: beginFormalParameters((, MemberKind.StaticMethod)
-                    parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.StaticMethod)
+              parseGetterOrFormalParameters(addChild, addChild, false, MemberKind.ExtensionStaticMethod)
+                parseFormalParameters(addChild, MemberKind.ExtensionStaticMethod)
+                  parseFormalParametersRest((, MemberKind.ExtensionStaticMethod)
+                    listener: beginFormalParameters((, MemberKind.ExtensionStaticMethod)
+                    parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.ExtensionStaticMethod)
                       parseMetadataStar(()
                         listener: beginMetadataStar(A)
                         listener: endMetadataStar(0)
-                      listener: beginFormalParameter(A, MemberKind.StaticMethod, null, null, null)
+                      listener: beginFormalParameter(A, MemberKind.ExtensionStaticMethod, null, null, null)
                       listener: handleIdentifier(A, typeReference)
                       listener: handleNoTypeArguments(child)
                       listener: handleType(A, null)
                       ensureIdentifier(A, formalParameterDeclaration)
                         listener: handleIdentifier(child, formalParameterDeclaration)
                       listener: handleFormalParameterWithoutValue())
-                      listener: endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.StaticMethod)
-                    listener: endFormalParameters(1, (, ), MemberKind.StaticMethod)
+                      listener: endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.ExtensionStaticMethod)
+                    listener: endFormalParameters(1, (, ), MemberKind.ExtensionStaticMethod)
               parseInitializersOpt())
                 listener: handleNoInitializers()
               parseAsyncModifierOpt())
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 f953361..434aa58 100644
--- a/pkg/front_end/parser_testcases/extensions/static_covariant.dart.expect
+++ b/pkg/front_end/parser_testcases/extensions/static_covariant.dart.expect
@@ -47,18 +47,18 @@
             handleNoType(static)
             handleIdentifier(addChild, methodDeclaration)
             handleNoTypeVariables(()
-            beginFormalParameters((, MemberKind.StaticMethod)
+            beginFormalParameters((, MemberKind.ExtensionStaticMethod)
               beginMetadataStar(covariant)
               endMetadataStar(0)
-              handleRecoverableError(Instance of 'Message', covariant, covariant)
-              beginFormalParameter(covariant, MemberKind.StaticMethod, null, null, null)
+              handleRecoverableError(Message[ExtraneousModifierInExtension, Can't have modifier 'covariant' in an extension., Try removing 'covariant'., {token: covariant}], covariant, covariant)
+              beginFormalParameter(covariant, MemberKind.ExtensionStaticMethod, null, null, null)
                 handleIdentifier(A, typeReference)
                 handleNoTypeArguments(child)
                 handleType(A, null)
                 handleIdentifier(child, formalParameterDeclaration)
                 handleFormalParameterWithoutValue())
-              endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.StaticMethod)
-            endFormalParameters(1, (, ), MemberKind.StaticMethod)
+              endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.ExtensionStaticMethod)
+            endFormalParameters(1, (, ), MemberKind.ExtensionStaticMethod)
             handleNoInitializers()
             handleAsyncModifier(null, null)
             beginBlockFunctionBody({)
diff --git a/pkg/front_end/parser_testcases/extensions/static_covariant.dart.intertwined.expect b/pkg/front_end/parser_testcases/extensions/static_covariant.dart.intertwined.expect
index 43cdc41..260abee 100644
--- a/pkg/front_end/parser_testcases/extensions/static_covariant.dart.intertwined.expect
+++ b/pkg/front_end/parser_testcases/extensions/static_covariant.dart.intertwined.expect
@@ -89,25 +89,25 @@
               parseQualifiedRestOpt(addChild, methodDeclarationContinuation)
               parseMethodTypeVar(addChild)
                 listener: handleNoTypeVariables(()
-              parseGetterOrFormalParameters(addChild, addChild, false, MemberKind.StaticMethod)
-                parseFormalParameters(addChild, MemberKind.StaticMethod)
-                  parseFormalParametersRest((, MemberKind.StaticMethod)
-                    listener: beginFormalParameters((, MemberKind.StaticMethod)
-                    parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.StaticMethod)
+              parseGetterOrFormalParameters(addChild, addChild, false, MemberKind.ExtensionStaticMethod)
+                parseFormalParameters(addChild, MemberKind.ExtensionStaticMethod)
+                  parseFormalParametersRest((, MemberKind.ExtensionStaticMethod)
+                    listener: beginFormalParameters((, MemberKind.ExtensionStaticMethod)
+                    parseFormalParameter((, FormalParameterKind.mandatory, MemberKind.ExtensionStaticMethod)
                       parseMetadataStar(()
                         listener: beginMetadataStar(covariant)
                         listener: endMetadataStar(0)
                       reportRecoverableErrorWithToken(covariant, Instance of 'Template<(Token) => Message>')
-                        listener: handleRecoverableError(Instance of 'Message', covariant, covariant)
-                      listener: beginFormalParameter(covariant, MemberKind.StaticMethod, null, null, null)
+                        listener: handleRecoverableError(Message[ExtraneousModifierInExtension, Can't have modifier 'covariant' in an extension., Try removing 'covariant'., {token: covariant}], covariant, covariant)
+                      listener: beginFormalParameter(covariant, MemberKind.ExtensionStaticMethod, null, null, null)
                       listener: handleIdentifier(A, typeReference)
                       listener: handleNoTypeArguments(child)
                       listener: handleType(A, null)
                       ensureIdentifier(A, formalParameterDeclaration)
                         listener: handleIdentifier(child, formalParameterDeclaration)
                       listener: handleFormalParameterWithoutValue())
-                      listener: endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.StaticMethod)
-                    listener: endFormalParameters(1, (, ), MemberKind.StaticMethod)
+                      listener: endFormalParameter(null, null, child, null, null, FormalParameterKind.mandatory, MemberKind.ExtensionStaticMethod)
+                    listener: endFormalParameters(1, (, ), MemberKind.ExtensionStaticMethod)
               parseInitializersOpt())
                 listener: handleNoInitializers()
               parseAsyncModifierOpt())
diff --git a/pkg/front_end/parser_testcases/nnbd/late_member.dart b/pkg/front_end/parser_testcases/nnbd/late_member.dart
new file mode 100644
index 0000000..ad346ee
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/late_member.dart
@@ -0,0 +1,22 @@
+main() {
+  dynamic foo = new X();
+  var bar = foo.late;
+  late();
+  bar();
+  new X().late();
+  new Y().late;
+}
+
+late() {
+  print("hello");
+}
+
+class X {
+  late() {
+    print("hello");
+  }
+}
+
+class Y {
+  int late = 42;
+}
diff --git a/pkg/front_end/parser_testcases/nnbd/late_member.dart.expect b/pkg/front_end/parser_testcases/nnbd/late_member.dart.expect
new file mode 100644
index 0000000..63f0893
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/late_member.dart.expect
@@ -0,0 +1,186 @@
+beginCompilationUnit(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(dynamic)
+        endMetadataStar(0)
+        handleIdentifier(dynamic, typeReference)
+        handleNoTypeArguments(foo)
+        handleType(dynamic, null)
+        beginVariablesDeclaration(foo, null, null)
+          handleIdentifier(foo, localVariableDeclaration)
+          beginInitializedIdentifier(foo)
+            beginVariableInitializer(=)
+              beginNewExpression(new)
+                handleIdentifier(X, constructorReference)
+                beginConstructorReference(X)
+                  handleNoTypeArguments(()
+                  handleNoConstructorReferenceContinuationAfterTypeArguments(()
+                endConstructorReference(X, null, ()
+                beginArguments(()
+                endArguments(0, (, ))
+              endNewExpression(new)
+            endVariableInitializer(=)
+          endInitializedIdentifier(foo)
+        endVariablesDeclaration(1, ;)
+        beginMetadataStar(var)
+        endMetadataStar(0)
+        handleNoType(var)
+        beginVariablesDeclaration(bar, null, var)
+          handleIdentifier(bar, localVariableDeclaration)
+          beginInitializedIdentifier(bar)
+            beginVariableInitializer(=)
+              handleIdentifier(foo, expression)
+              handleNoTypeArguments(.)
+              handleNoArguments(.)
+              handleSend(foo, .)
+              handleIdentifier(late, expressionContinuation)
+              handleNoTypeArguments(;)
+              handleNoArguments(;)
+              handleSend(late, ;)
+            endBinaryExpression(.)
+          endVariableInitializer(=)
+        endInitializedIdentifier(bar)
+      endVariablesDeclaration(1, ;)
+      handleIdentifier(late, expression)
+      handleNoTypeArguments(()
+      beginArguments(()
+      endArguments(0, (, ))
+      handleSend(late, ;)
+      handleExpressionStatement(;)
+      handleIdentifier(bar, expression)
+      handleNoTypeArguments(()
+      beginArguments(()
+      endArguments(0, (, ))
+      handleSend(bar, ;)
+      handleExpressionStatement(;)
+      beginNewExpression(new)
+        handleIdentifier(X, constructorReference)
+        beginConstructorReference(X)
+          handleNoTypeArguments(()
+          handleNoConstructorReferenceContinuationAfterTypeArguments(()
+        endConstructorReference(X, null, ()
+        beginArguments(()
+        endArguments(0, (, ))
+      endNewExpression(new)
+      handleIdentifier(late, expressionContinuation)
+      handleNoTypeArguments(()
+      beginArguments(()
+      endArguments(0, (, ))
+      handleSend(late, ;)
+    endBinaryExpression(.)
+    handleExpressionStatement(;)
+    beginNewExpression(new)
+      handleIdentifier(Y, constructorReference)
+      beginConstructorReference(Y)
+        handleNoTypeArguments(()
+        handleNoConstructorReferenceContinuationAfterTypeArguments(()
+      endConstructorReference(Y, null, ()
+      beginArguments(()
+      endArguments(0, (, ))
+    endNewExpression(new)
+    handleIdentifier(late, expressionContinuation)
+    handleNoTypeArguments(;)
+    handleNoArguments(;)
+    handleSend(late, ;)
+  endBinaryExpression(.)
+  handleExpressionStatement(;)
+endBlockFunctionBody(6, {, })
+endTopLevelMethod(main, null, })
+endTopLevelDeclaration(late)
+beginMetadataStar(late)
+endMetadataStar(0)
+beginTopLevelMember(late)
+beginTopLevelMethod(}, null)
+handleNoType(})
+handleIdentifier(late, topLevelFunctionDeclaration)
+handleNoTypeVariables(()
+beginFormalParameters((, MemberKind.TopLevelMethod)
+endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+handleAsyncModifier(null, null)
+beginBlockFunctionBody({)
+  handleIdentifier(print, expression)
+  handleNoTypeArguments(()
+  beginArguments(()
+    beginLiteralString("hello")
+    endLiteralString(0, ))
+  endArguments(1, (, ))
+  handleSend(print, ;)
+  handleExpressionStatement(;)
+endBlockFunctionBody(1, {, })
+endTopLevelMethod(late, null, })
+endTopLevelDeclaration(class)
+beginMetadataStar(class)
+endMetadataStar(0)
+beginClassOrNamedMixinApplicationPrelude(class)
+handleIdentifier(X, classOrMixinDeclaration)
+handleNoTypeVariables({)
+beginClassDeclaration(class, null, X)
+handleNoType(X)
+handleClassExtends(null)
+handleClassNoWithClause()
+handleClassOrMixinImplements(null, 0)
+handleClassHeader(class, class, null)
+beginClassOrMixinBody(DeclarationKind.Class, {)
+  beginMetadataStar(late)
+  endMetadataStar(0)
+  beginMember()
+    beginMethod(null, null, null, null, null, late)
+      handleNoType({)
+      handleIdentifier(late, methodDeclaration)
+      handleNoTypeVariables(()
+      beginFormalParameters((, MemberKind.NonStaticMethod)
+      endFormalParameters(0, (, ), MemberKind.NonStaticMethod)
+      handleNoInitializers()
+      handleAsyncModifier(null, null)
+      beginBlockFunctionBody({)
+        handleIdentifier(print, expression)
+        handleNoTypeArguments(()
+        beginArguments(()
+          beginLiteralString("hello")
+          endLiteralString(0, ))
+        endArguments(1, (, ))
+        handleSend(print, ;)
+        handleExpressionStatement(;)
+      endBlockFunctionBody(1, {, })
+    endClassMethod(null, late, (, null, })
+  endMember()
+endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+endClassDeclaration(class, })
+endTopLevelDeclaration(class)
+beginMetadataStar(class)
+endMetadataStar(0)
+beginClassOrNamedMixinApplicationPrelude(class)
+handleIdentifier(Y, classOrMixinDeclaration)
+handleNoTypeVariables({)
+beginClassDeclaration(class, null, Y)
+handleNoType(Y)
+handleClassExtends(null)
+handleClassNoWithClause()
+handleClassOrMixinImplements(null, 0)
+handleClassHeader(class, class, null)
+beginClassOrMixinBody(DeclarationKind.Class, {)
+  beginMetadataStar(int)
+  endMetadataStar(0)
+  beginMember()
+    handleIdentifier(int, typeReference)
+    handleNoTypeArguments(late)
+    handleType(int, null)
+    handleIdentifier(late, fieldDeclaration)
+    beginFieldInitializer(=)
+      handleLiteralInt(42)
+    endFieldInitializer(=, ;)
+  endClassFields(null, null, null, null, 1, int, ;)
+endMember()
+endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+endClassDeclaration(class, })
+endTopLevelDeclaration()
+endCompilationUnit(4, )
diff --git a/pkg/front_end/parser_testcases/nnbd/late_member.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/late_member.dart.intertwined.expect
new file mode 100644
index 0000000..d385dd5
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/late_member.dart.intertwined.expect
@@ -0,0 +1,455 @@
+parseUnit(main)
+  skipErrorTokens(main)
+  listener: beginCompilationUnit(main)
+  syntheticPreviousToken(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(}, dynamic)
+          parseStatement({)
+            parseStatementX({)
+              parseExpressionStatementOrDeclaration({, false)
+                parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+                  looksLikeLocalFunction(foo)
+                  listener: beginMetadataStar(dynamic)
+                  listener: endMetadataStar(0)
+                  listener: handleIdentifier(dynamic, typeReference)
+                  listener: handleNoTypeArguments(foo)
+                  listener: handleType(dynamic, null)
+                  listener: beginVariablesDeclaration(foo, null, null)
+                  parseVariablesDeclarationRest(dynamic, true)
+                    parseOptionallyInitializedIdentifier(dynamic)
+                      ensureIdentifier(dynamic, localVariableDeclaration)
+                        listener: handleIdentifier(foo, localVariableDeclaration)
+                      listener: beginInitializedIdentifier(foo)
+                      parseVariableInitializerOpt(foo)
+                        listener: beginVariableInitializer(=)
+                        parseExpression(=)
+                          parsePrecedenceExpression(=, 1, true)
+                            parseUnaryExpression(=, true)
+                              parsePrimary(=, expression)
+                                parseNewExpression(=)
+                                  listener: beginNewExpression(new)
+                                  parseConstructorReference(new, null)
+                                    ensureIdentifier(new, constructorReference)
+                                      listener: handleIdentifier(X, constructorReference)
+                                    listener: beginConstructorReference(X)
+                                    parseQualifiedRestOpt(X, constructorReferenceContinuation)
+                                    listener: handleNoTypeArguments(()
+                                    listener: handleNoConstructorReferenceContinuationAfterTypeArguments(()
+                                    listener: endConstructorReference(X, null, ()
+                                  parseConstructorInvocationArguments(X)
+                                    parseArgumentsRest(()
+                                      listener: beginArguments(()
+                                      listener: endArguments(0, (, ))
+                                  listener: endNewExpression(new)
+                        listener: endVariableInitializer(=)
+                      listener: endInitializedIdentifier(foo)
+                    ensureSemicolon())
+                    listener: endVariablesDeclaration(1, ;)
+          notEofOrValue(}, var)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclarationAfterModifiers(var, ;, null, var, null, false)
+                looksLikeLocalFunction(bar)
+                listener: beginMetadataStar(var)
+                listener: endMetadataStar(0)
+                listener: handleNoType(var)
+                listener: beginVariablesDeclaration(bar, null, var)
+                parseVariablesDeclarationRest(var, true)
+                  parseOptionallyInitializedIdentifier(var)
+                    ensureIdentifier(var, localVariableDeclaration)
+                      listener: handleIdentifier(bar, localVariableDeclaration)
+                    listener: beginInitializedIdentifier(bar)
+                    parseVariableInitializerOpt(bar)
+                      listener: beginVariableInitializer(=)
+                      parseExpression(=)
+                        parsePrecedenceExpression(=, 1, true)
+                          parseUnaryExpression(=, true)
+                            parsePrimary(=, expression)
+                              parseSendOrFunctionLiteral(=, expression)
+                                parseSend(=, expression)
+                                  ensureIdentifier(=, expression)
+                                    listener: handleIdentifier(foo, expression)
+                                  listener: handleNoTypeArguments(.)
+                                  parseArgumentsOpt(foo)
+                                    listener: handleNoArguments(.)
+                                  listener: handleSend(foo, .)
+                          parsePrimary(., expressionContinuation)
+                            inPlainSync()
+                            parseSendOrFunctionLiteral(., expressionContinuation)
+                              parseSend(., expressionContinuation)
+                                ensureIdentifier(., expressionContinuation)
+                                  inPlainSync()
+                                  listener: handleIdentifier(late, expressionContinuation)
+                                listener: handleNoTypeArguments(;)
+                                parseArgumentsOpt(late)
+                                  listener: handleNoArguments(;)
+                                listener: handleSend(late, ;)
+                          listener: endBinaryExpression(.)
+                      listener: endVariableInitializer(=)
+                    listener: endInitializedIdentifier(bar)
+                  ensureSemicolon(late)
+                  listener: endVariablesDeclaration(1, ;)
+          notEofOrValue(}, late)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclaration(;, false)
+                parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+                  looksLikeLocalFunction(late)
+                  parseExpressionStatement(;)
+                    parseExpression(;)
+                      parsePrecedenceExpression(;, 1, true)
+                        parseUnaryExpression(;, true)
+                          parsePrimary(;, expression)
+                            inPlainSync()
+                            parseSendOrFunctionLiteral(;, expression)
+                              looksLikeFunctionBody(;)
+                              parseSend(;, expression)
+                                ensureIdentifier(;, expression)
+                                  inPlainSync()
+                                  listener: handleIdentifier(late, expression)
+                                listener: handleNoTypeArguments(()
+                                parseArgumentsOpt(late)
+                                  parseArguments(late)
+                                    parseArgumentsRest(()
+                                      listener: beginArguments(()
+                                      listener: endArguments(0, (, ))
+                                listener: handleSend(late, ;)
+                    ensureSemicolon())
+                    listener: handleExpressionStatement(;)
+          notEofOrValue(}, bar)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+                looksLikeLocalFunction(bar)
+                parseExpressionStatement(;)
+                  parseExpression(;)
+                    parsePrecedenceExpression(;, 1, true)
+                      parseUnaryExpression(;, true)
+                        parsePrimary(;, expression)
+                          parseSendOrFunctionLiteral(;, expression)
+                            looksLikeFunctionBody(;)
+                            parseSend(;, expression)
+                              ensureIdentifier(;, expression)
+                                listener: handleIdentifier(bar, expression)
+                              listener: handleNoTypeArguments(()
+                              parseArgumentsOpt(bar)
+                                parseArguments(bar)
+                                  parseArgumentsRest(()
+                                    listener: beginArguments(()
+                                    listener: endArguments(0, (, ))
+                              listener: handleSend(bar, ;)
+                  ensureSemicolon())
+                  listener: handleExpressionStatement(;)
+          notEofOrValue(}, new)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclaration(;, false)
+                parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+                  looksLikeLocalFunction(new)
+                  parseExpressionStatement(;)
+                    parseExpression(;)
+                      parsePrecedenceExpression(;, 1, true)
+                        parseUnaryExpression(;, true)
+                          parsePrimary(;, expression)
+                            parseNewExpression(;)
+                              listener: beginNewExpression(new)
+                              parseConstructorReference(new, null)
+                                ensureIdentifier(new, constructorReference)
+                                  listener: handleIdentifier(X, constructorReference)
+                                listener: beginConstructorReference(X)
+                                parseQualifiedRestOpt(X, constructorReferenceContinuation)
+                                listener: handleNoTypeArguments(()
+                                listener: handleNoConstructorReferenceContinuationAfterTypeArguments(()
+                                listener: endConstructorReference(X, null, ()
+                              parseConstructorInvocationArguments(X)
+                                parseArgumentsRest(()
+                                  listener: beginArguments(()
+                                  listener: endArguments(0, (, ))
+                              listener: endNewExpression(new)
+                        parsePrimary(., expressionContinuation)
+                          inPlainSync()
+                          parseSendOrFunctionLiteral(., expressionContinuation)
+                            looksLikeFunctionBody(;)
+                            parseSend(., expressionContinuation)
+                              ensureIdentifier(., expressionContinuation)
+                                inPlainSync()
+                                listener: handleIdentifier(late, expressionContinuation)
+                              listener: handleNoTypeArguments(()
+                              parseArgumentsOpt(late)
+                                parseArguments(late)
+                                  parseArgumentsRest(()
+                                    listener: beginArguments(()
+                                    listener: endArguments(0, (, ))
+                              listener: handleSend(late, ;)
+                        listener: endBinaryExpression(.)
+                    ensureSemicolon())
+                    listener: handleExpressionStatement(;)
+          notEofOrValue(}, new)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclaration(;, false)
+                parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+                  looksLikeLocalFunction(new)
+                  parseExpressionStatement(;)
+                    parseExpression(;)
+                      parsePrecedenceExpression(;, 1, true)
+                        parseUnaryExpression(;, true)
+                          parsePrimary(;, expression)
+                            parseNewExpression(;)
+                              listener: beginNewExpression(new)
+                              parseConstructorReference(new, null)
+                                ensureIdentifier(new, constructorReference)
+                                  listener: handleIdentifier(Y, constructorReference)
+                                listener: beginConstructorReference(Y)
+                                parseQualifiedRestOpt(Y, constructorReferenceContinuation)
+                                listener: handleNoTypeArguments(()
+                                listener: handleNoConstructorReferenceContinuationAfterTypeArguments(()
+                                listener: endConstructorReference(Y, null, ()
+                              parseConstructorInvocationArguments(Y)
+                                parseArgumentsRest(()
+                                  listener: beginArguments(()
+                                  listener: endArguments(0, (, ))
+                              listener: endNewExpression(new)
+                        parsePrimary(., expressionContinuation)
+                          inPlainSync()
+                          parseSendOrFunctionLiteral(., expressionContinuation)
+                            parseSend(., expressionContinuation)
+                              ensureIdentifier(., expressionContinuation)
+                                inPlainSync()
+                                listener: handleIdentifier(late, expressionContinuation)
+                              listener: handleNoTypeArguments(;)
+                              parseArgumentsOpt(late)
+                                listener: handleNoArguments(;)
+                              listener: handleSend(late, ;)
+                        listener: endBinaryExpression(.)
+                    ensureSemicolon(late)
+                    listener: handleExpressionStatement(;)
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(6, {, })
+        listener: endTopLevelMethod(main, null, })
+  listener: endTopLevelDeclaration(late)
+  parseTopLevelDeclarationImpl(}, Instance of 'DirectiveContext')
+    parseMetadataStar(})
+      listener: beginMetadataStar(late)
+      listener: endMetadataStar(0)
+    parseTopLevelMemberImpl(})
+      listener: beginTopLevelMember(late)
+      parseTopLevelMethod(}, null, }, Instance of 'NoType', null, late)
+        listener: beginTopLevelMethod(}, null)
+        listener: handleNoType(})
+        ensureIdentifier(}, topLevelFunctionDeclaration)
+          listener: handleIdentifier(late, topLevelFunctionDeclaration)
+        parseMethodTypeVar(late)
+          listener: handleNoTypeVariables(()
+        parseGetterOrFormalParameters(late, late, false, MemberKind.TopLevelMethod)
+          parseFormalParameters(late, 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(}, print)
+          parseStatement({)
+            parseStatementX({)
+              parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+                looksLikeLocalFunction(print)
+                parseExpressionStatement({)
+                  parseExpression({)
+                    parsePrecedenceExpression({, 1, true)
+                      parseUnaryExpression({, true)
+                        parsePrimary({, expression)
+                          parseSendOrFunctionLiteral({, expression)
+                            looksLikeFunctionBody(;)
+                            parseSend({, expression)
+                              ensureIdentifier({, expression)
+                                listener: handleIdentifier(print, expression)
+                              listener: handleNoTypeArguments(()
+                              parseArgumentsOpt(print)
+                                parseArguments(print)
+                                  parseArgumentsRest(()
+                                    listener: beginArguments(()
+                                    parseExpression(()
+                                      parsePrecedenceExpression((, 1, true)
+                                        parseUnaryExpression((, true)
+                                          parsePrimary((, expression)
+                                            parseLiteralString(()
+                                              parseSingleLiteralString(()
+                                                listener: beginLiteralString("hello")
+                                                listener: endLiteralString(0, ))
+                                    listener: endArguments(1, (, ))
+                              listener: handleSend(print, ;)
+                  ensureSemicolon())
+                  listener: handleExpressionStatement(;)
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(1, {, })
+        listener: endTopLevelMethod(late, null, })
+  listener: endTopLevelDeclaration(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(X, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, X)
+        parseClass(X, class, class, X)
+          parseClassHeaderOpt(X, class, class)
+            parseClassExtendsOpt(X)
+              listener: handleNoType(X)
+              listener: handleClassExtends(null)
+            parseWithClauseOpt(X)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(X)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(X, DeclarationKind.Class, X)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, late)
+            parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, X)
+              parseMetadataStar({)
+                listener: beginMetadataStar(late)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              parseMethod({, null, null, null, null, null, {, Instance of 'NoType', null, late, DeclarationKind.Class, X)
+                listener: beginMethod(null, null, null, null, null, late)
+                listener: handleNoType({)
+                ensureIdentifier({, methodDeclaration)
+                  listener: handleIdentifier(late, methodDeclaration)
+                parseQualifiedRestOpt(late, methodDeclarationContinuation)
+                parseMethodTypeVar(late)
+                  listener: handleNoTypeVariables(()
+                parseGetterOrFormalParameters(late, late, false, MemberKind.NonStaticMethod)
+                  parseFormalParameters(late, MemberKind.NonStaticMethod)
+                    parseFormalParametersRest((, MemberKind.NonStaticMethod)
+                      listener: beginFormalParameters((, MemberKind.NonStaticMethod)
+                      listener: endFormalParameters(0, (, ), MemberKind.NonStaticMethod)
+                parseInitializersOpt())
+                  listener: handleNoInitializers()
+                parseAsyncModifierOpt())
+                  listener: handleAsyncModifier(null, null)
+                  inPlainSync()
+                inPlainSync()
+                parseFunctionBody(), false, true)
+                  listener: beginBlockFunctionBody({)
+                  notEofOrValue(}, print)
+                  parseStatement({)
+                    parseStatementX({)
+                      parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+                        looksLikeLocalFunction(print)
+                        parseExpressionStatement({)
+                          parseExpression({)
+                            parsePrecedenceExpression({, 1, true)
+                              parseUnaryExpression({, true)
+                                parsePrimary({, expression)
+                                  parseSendOrFunctionLiteral({, expression)
+                                    looksLikeFunctionBody(;)
+                                    parseSend({, expression)
+                                      ensureIdentifier({, expression)
+                                        listener: handleIdentifier(print, expression)
+                                      listener: handleNoTypeArguments(()
+                                      parseArgumentsOpt(print)
+                                        parseArguments(print)
+                                          parseArgumentsRest(()
+                                            listener: beginArguments(()
+                                            parseExpression(()
+                                              parsePrecedenceExpression((, 1, true)
+                                                parseUnaryExpression((, true)
+                                                  parsePrimary((, expression)
+                                                    parseLiteralString(()
+                                                      parseSingleLiteralString(()
+                                                        listener: beginLiteralString("hello")
+                                                        listener: endLiteralString(0, ))
+                                            listener: endArguments(1, (, ))
+                                      listener: handleSend(print, ;)
+                          ensureSemicolon())
+                          listener: handleExpressionStatement(;)
+                  notEofOrValue(}, })
+                  listener: endBlockFunctionBody(1, {, })
+                listener: endClassMethod(null, late, (, null, })
+              listener: endMember()
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration(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(Y, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, Y)
+        parseClass(Y, class, class, Y)
+          parseClassHeaderOpt(Y, class, class)
+            parseClassExtendsOpt(Y)
+              listener: handleNoType(Y)
+              listener: handleClassExtends(null)
+            parseWithClauseOpt(Y)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(Y)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(Y, DeclarationKind.Class, Y)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, int)
+            parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, Y)
+              parseMetadataStar({)
+                listener: beginMetadataStar(int)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              parseFields({, null, null, null, null, null, {, Instance of 'SimpleType', late, DeclarationKind.Class)
+                listener: handleIdentifier(int, typeReference)
+                listener: handleNoTypeArguments(late)
+                listener: handleType(int, null)
+                ensureIdentifier(int, fieldDeclaration)
+                  listener: handleIdentifier(late, fieldDeclaration)
+                parseFieldInitializerOpt(late, late, null, null, DeclarationKind.Class)
+                  listener: beginFieldInitializer(=)
+                  parseExpression(=)
+                    parsePrecedenceExpression(=, 1, true)
+                      parseUnaryExpression(=, true)
+                        parsePrimary(=, expression)
+                          parseLiteralInt(=)
+                            listener: handleLiteralInt(42)
+                  listener: endFieldInitializer(=, ;)
+                listener: endClassFields(null, null, null, null, 1, int, ;)
+              listener: endMember()
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(main)
+  listener: endCompilationUnit(4, )
diff --git a/pkg/front_end/parser_testcases/nnbd/late_modifier.dart b/pkg/front_end/parser_testcases/nnbd/late_modifier.dart
new file mode 100644
index 0000000..e1b6d80
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/late_modifier.dart
@@ -0,0 +1,26 @@
+main() {
+  dynamic foo = new X();
+  var bar = foo.late;
+  late();
+  bar();
+  new X().late();
+  new Y().late;
+  
+  // And now the late modifiers
+  late int foo;
+  foo = 42;
+}
+
+late() {
+  print("hello");
+}
+
+class X {
+  late() {
+    print("hello");
+  }
+}
+
+class Y {
+  int late = 42;
+}
diff --git a/pkg/front_end/parser_testcases/nnbd/late_modifier.dart.expect b/pkg/front_end/parser_testcases/nnbd/late_modifier.dart.expect
new file mode 100644
index 0000000..1a915bd
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/late_modifier.dart.expect
@@ -0,0 +1,204 @@
+beginCompilationUnit(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(dynamic)
+        endMetadataStar(0)
+        handleIdentifier(dynamic, typeReference)
+        handleNoTypeArguments(foo)
+        handleType(dynamic, null)
+        beginVariablesDeclaration(foo, null, null)
+          handleIdentifier(foo, localVariableDeclaration)
+          beginInitializedIdentifier(foo)
+            beginVariableInitializer(=)
+              beginNewExpression(new)
+                handleIdentifier(X, constructorReference)
+                beginConstructorReference(X)
+                  handleNoTypeArguments(()
+                  handleNoConstructorReferenceContinuationAfterTypeArguments(()
+                endConstructorReference(X, null, ()
+                beginArguments(()
+                endArguments(0, (, ))
+              endNewExpression(new)
+            endVariableInitializer(=)
+          endInitializedIdentifier(foo)
+        endVariablesDeclaration(1, ;)
+        beginMetadataStar(var)
+        endMetadataStar(0)
+        handleNoType(var)
+        beginVariablesDeclaration(bar, null, var)
+          handleIdentifier(bar, localVariableDeclaration)
+          beginInitializedIdentifier(bar)
+            beginVariableInitializer(=)
+              handleIdentifier(foo, expression)
+              handleNoTypeArguments(.)
+              handleNoArguments(.)
+              handleSend(foo, .)
+              handleIdentifier(late, expressionContinuation)
+              handleNoTypeArguments(;)
+              handleNoArguments(;)
+              handleSend(late, ;)
+            endBinaryExpression(.)
+          endVariableInitializer(=)
+        endInitializedIdentifier(bar)
+      endVariablesDeclaration(1, ;)
+      handleIdentifier(late, expression)
+      handleNoTypeArguments(()
+      beginArguments(()
+      endArguments(0, (, ))
+      handleSend(late, ;)
+      handleExpressionStatement(;)
+      handleIdentifier(bar, expression)
+      handleNoTypeArguments(()
+      beginArguments(()
+      endArguments(0, (, ))
+      handleSend(bar, ;)
+      handleExpressionStatement(;)
+      beginNewExpression(new)
+        handleIdentifier(X, constructorReference)
+        beginConstructorReference(X)
+          handleNoTypeArguments(()
+          handleNoConstructorReferenceContinuationAfterTypeArguments(()
+        endConstructorReference(X, null, ()
+        beginArguments(()
+        endArguments(0, (, ))
+      endNewExpression(new)
+      handleIdentifier(late, expressionContinuation)
+      handleNoTypeArguments(()
+      beginArguments(()
+      endArguments(0, (, ))
+      handleSend(late, ;)
+    endBinaryExpression(.)
+    handleExpressionStatement(;)
+    beginNewExpression(new)
+      handleIdentifier(Y, constructorReference)
+      beginConstructorReference(Y)
+        handleNoTypeArguments(()
+        handleNoConstructorReferenceContinuationAfterTypeArguments(()
+      endConstructorReference(Y, null, ()
+      beginArguments(()
+      endArguments(0, (, ))
+    endNewExpression(new)
+    handleIdentifier(late, expressionContinuation)
+    handleNoTypeArguments(;)
+    handleNoArguments(;)
+    handleSend(late, ;)
+  endBinaryExpression(.)
+  handleExpressionStatement(;)
+  beginMetadataStar(late)
+  endMetadataStar(0)
+  handleIdentifier(int, typeReference)
+  handleNoTypeArguments(foo)
+  handleType(int, null)
+  beginVariablesDeclaration(foo, late, null)
+    handleIdentifier(foo, localVariableDeclaration)
+    beginInitializedIdentifier(foo)
+      handleNoVariableInitializer(;)
+    endInitializedIdentifier(foo)
+  endVariablesDeclaration(1, ;)
+  handleIdentifier(foo, expression)
+  handleNoTypeArguments(=)
+  handleNoArguments(=)
+  handleSend(foo, =)
+  handleLiteralInt(42)
+  handleAssignmentExpression(=)
+  handleExpressionStatement(;)
+endBlockFunctionBody(8, {, })
+endTopLevelMethod(main, null, })
+endTopLevelDeclaration(late)
+beginMetadataStar(late)
+endMetadataStar(0)
+beginTopLevelMember(late)
+beginTopLevelMethod(}, null)
+handleNoType(})
+handleIdentifier(late, topLevelFunctionDeclaration)
+handleNoTypeVariables(()
+beginFormalParameters((, MemberKind.TopLevelMethod)
+endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+handleAsyncModifier(null, null)
+beginBlockFunctionBody({)
+  handleIdentifier(print, expression)
+  handleNoTypeArguments(()
+  beginArguments(()
+    beginLiteralString("hello")
+    endLiteralString(0, ))
+  endArguments(1, (, ))
+  handleSend(print, ;)
+  handleExpressionStatement(;)
+endBlockFunctionBody(1, {, })
+endTopLevelMethod(late, null, })
+endTopLevelDeclaration(class)
+beginMetadataStar(class)
+endMetadataStar(0)
+beginClassOrNamedMixinApplicationPrelude(class)
+handleIdentifier(X, classOrMixinDeclaration)
+handleNoTypeVariables({)
+beginClassDeclaration(class, null, X)
+handleNoType(X)
+handleClassExtends(null)
+handleClassNoWithClause()
+handleClassOrMixinImplements(null, 0)
+handleClassHeader(class, class, null)
+beginClassOrMixinBody(DeclarationKind.Class, {)
+  beginMetadataStar(late)
+  endMetadataStar(0)
+  beginMember()
+    beginMethod(null, null, null, null, null, late)
+      handleNoType({)
+      handleIdentifier(late, methodDeclaration)
+      handleNoTypeVariables(()
+      beginFormalParameters((, MemberKind.NonStaticMethod)
+      endFormalParameters(0, (, ), MemberKind.NonStaticMethod)
+      handleNoInitializers()
+      handleAsyncModifier(null, null)
+      beginBlockFunctionBody({)
+        handleIdentifier(print, expression)
+        handleNoTypeArguments(()
+        beginArguments(()
+          beginLiteralString("hello")
+          endLiteralString(0, ))
+        endArguments(1, (, ))
+        handleSend(print, ;)
+        handleExpressionStatement(;)
+      endBlockFunctionBody(1, {, })
+    endClassMethod(null, late, (, null, })
+  endMember()
+endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+endClassDeclaration(class, })
+endTopLevelDeclaration(class)
+beginMetadataStar(class)
+endMetadataStar(0)
+beginClassOrNamedMixinApplicationPrelude(class)
+handleIdentifier(Y, classOrMixinDeclaration)
+handleNoTypeVariables({)
+beginClassDeclaration(class, null, Y)
+handleNoType(Y)
+handleClassExtends(null)
+handleClassNoWithClause()
+handleClassOrMixinImplements(null, 0)
+handleClassHeader(class, class, null)
+beginClassOrMixinBody(DeclarationKind.Class, {)
+  beginMetadataStar(int)
+  endMetadataStar(0)
+  beginMember()
+    handleIdentifier(int, typeReference)
+    handleNoTypeArguments(late)
+    handleType(int, null)
+    handleIdentifier(late, fieldDeclaration)
+    beginFieldInitializer(=)
+      handleLiteralInt(42)
+    endFieldInitializer(=, ;)
+  endClassFields(null, null, null, null, 1, int, ;)
+endMember()
+endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+endClassDeclaration(class, })
+endTopLevelDeclaration()
+endCompilationUnit(4, )
diff --git a/pkg/front_end/parser_testcases/nnbd/late_modifier.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/late_modifier.dart.intertwined.expect
new file mode 100644
index 0000000..15d91f6
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/late_modifier.dart.intertwined.expect
@@ -0,0 +1,503 @@
+parseUnit(main)
+  skipErrorTokens(main)
+  listener: beginCompilationUnit(main)
+  syntheticPreviousToken(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(}, dynamic)
+          parseStatement({)
+            parseStatementX({)
+              parseExpressionStatementOrDeclaration({, false)
+                parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+                  looksLikeLocalFunction(foo)
+                  listener: beginMetadataStar(dynamic)
+                  listener: endMetadataStar(0)
+                  listener: handleIdentifier(dynamic, typeReference)
+                  listener: handleNoTypeArguments(foo)
+                  listener: handleType(dynamic, null)
+                  listener: beginVariablesDeclaration(foo, null, null)
+                  parseVariablesDeclarationRest(dynamic, true)
+                    parseOptionallyInitializedIdentifier(dynamic)
+                      ensureIdentifier(dynamic, localVariableDeclaration)
+                        listener: handleIdentifier(foo, localVariableDeclaration)
+                      listener: beginInitializedIdentifier(foo)
+                      parseVariableInitializerOpt(foo)
+                        listener: beginVariableInitializer(=)
+                        parseExpression(=)
+                          parsePrecedenceExpression(=, 1, true)
+                            parseUnaryExpression(=, true)
+                              parsePrimary(=, expression)
+                                parseNewExpression(=)
+                                  listener: beginNewExpression(new)
+                                  parseConstructorReference(new, null)
+                                    ensureIdentifier(new, constructorReference)
+                                      listener: handleIdentifier(X, constructorReference)
+                                    listener: beginConstructorReference(X)
+                                    parseQualifiedRestOpt(X, constructorReferenceContinuation)
+                                    listener: handleNoTypeArguments(()
+                                    listener: handleNoConstructorReferenceContinuationAfterTypeArguments(()
+                                    listener: endConstructorReference(X, null, ()
+                                  parseConstructorInvocationArguments(X)
+                                    parseArgumentsRest(()
+                                      listener: beginArguments(()
+                                      listener: endArguments(0, (, ))
+                                  listener: endNewExpression(new)
+                        listener: endVariableInitializer(=)
+                      listener: endInitializedIdentifier(foo)
+                    ensureSemicolon())
+                    listener: endVariablesDeclaration(1, ;)
+          notEofOrValue(}, var)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclarationAfterModifiers(var, ;, null, var, null, false)
+                looksLikeLocalFunction(bar)
+                listener: beginMetadataStar(var)
+                listener: endMetadataStar(0)
+                listener: handleNoType(var)
+                listener: beginVariablesDeclaration(bar, null, var)
+                parseVariablesDeclarationRest(var, true)
+                  parseOptionallyInitializedIdentifier(var)
+                    ensureIdentifier(var, localVariableDeclaration)
+                      listener: handleIdentifier(bar, localVariableDeclaration)
+                    listener: beginInitializedIdentifier(bar)
+                    parseVariableInitializerOpt(bar)
+                      listener: beginVariableInitializer(=)
+                      parseExpression(=)
+                        parsePrecedenceExpression(=, 1, true)
+                          parseUnaryExpression(=, true)
+                            parsePrimary(=, expression)
+                              parseSendOrFunctionLiteral(=, expression)
+                                parseSend(=, expression)
+                                  ensureIdentifier(=, expression)
+                                    listener: handleIdentifier(foo, expression)
+                                  listener: handleNoTypeArguments(.)
+                                  parseArgumentsOpt(foo)
+                                    listener: handleNoArguments(.)
+                                  listener: handleSend(foo, .)
+                          parsePrimary(., expressionContinuation)
+                            inPlainSync()
+                            parseSendOrFunctionLiteral(., expressionContinuation)
+                              parseSend(., expressionContinuation)
+                                ensureIdentifier(., expressionContinuation)
+                                  inPlainSync()
+                                  listener: handleIdentifier(late, expressionContinuation)
+                                listener: handleNoTypeArguments(;)
+                                parseArgumentsOpt(late)
+                                  listener: handleNoArguments(;)
+                                listener: handleSend(late, ;)
+                          listener: endBinaryExpression(.)
+                      listener: endVariableInitializer(=)
+                    listener: endInitializedIdentifier(bar)
+                  ensureSemicolon(late)
+                  listener: endVariablesDeclaration(1, ;)
+          notEofOrValue(}, late)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclaration(;, false)
+                parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+                  looksLikeLocalFunction(late)
+                  parseExpressionStatement(;)
+                    parseExpression(;)
+                      parsePrecedenceExpression(;, 1, true)
+                        parseUnaryExpression(;, true)
+                          parsePrimary(;, expression)
+                            inPlainSync()
+                            parseSendOrFunctionLiteral(;, expression)
+                              looksLikeFunctionBody(;)
+                              parseSend(;, expression)
+                                ensureIdentifier(;, expression)
+                                  inPlainSync()
+                                  listener: handleIdentifier(late, expression)
+                                listener: handleNoTypeArguments(()
+                                parseArgumentsOpt(late)
+                                  parseArguments(late)
+                                    parseArgumentsRest(()
+                                      listener: beginArguments(()
+                                      listener: endArguments(0, (, ))
+                                listener: handleSend(late, ;)
+                    ensureSemicolon())
+                    listener: handleExpressionStatement(;)
+          notEofOrValue(}, bar)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+                looksLikeLocalFunction(bar)
+                parseExpressionStatement(;)
+                  parseExpression(;)
+                    parsePrecedenceExpression(;, 1, true)
+                      parseUnaryExpression(;, true)
+                        parsePrimary(;, expression)
+                          parseSendOrFunctionLiteral(;, expression)
+                            looksLikeFunctionBody(;)
+                            parseSend(;, expression)
+                              ensureIdentifier(;, expression)
+                                listener: handleIdentifier(bar, expression)
+                              listener: handleNoTypeArguments(()
+                              parseArgumentsOpt(bar)
+                                parseArguments(bar)
+                                  parseArgumentsRest(()
+                                    listener: beginArguments(()
+                                    listener: endArguments(0, (, ))
+                              listener: handleSend(bar, ;)
+                  ensureSemicolon())
+                  listener: handleExpressionStatement(;)
+          notEofOrValue(}, new)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclaration(;, false)
+                parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+                  looksLikeLocalFunction(new)
+                  parseExpressionStatement(;)
+                    parseExpression(;)
+                      parsePrecedenceExpression(;, 1, true)
+                        parseUnaryExpression(;, true)
+                          parsePrimary(;, expression)
+                            parseNewExpression(;)
+                              listener: beginNewExpression(new)
+                              parseConstructorReference(new, null)
+                                ensureIdentifier(new, constructorReference)
+                                  listener: handleIdentifier(X, constructorReference)
+                                listener: beginConstructorReference(X)
+                                parseQualifiedRestOpt(X, constructorReferenceContinuation)
+                                listener: handleNoTypeArguments(()
+                                listener: handleNoConstructorReferenceContinuationAfterTypeArguments(()
+                                listener: endConstructorReference(X, null, ()
+                              parseConstructorInvocationArguments(X)
+                                parseArgumentsRest(()
+                                  listener: beginArguments(()
+                                  listener: endArguments(0, (, ))
+                              listener: endNewExpression(new)
+                        parsePrimary(., expressionContinuation)
+                          inPlainSync()
+                          parseSendOrFunctionLiteral(., expressionContinuation)
+                            looksLikeFunctionBody(;)
+                            parseSend(., expressionContinuation)
+                              ensureIdentifier(., expressionContinuation)
+                                inPlainSync()
+                                listener: handleIdentifier(late, expressionContinuation)
+                              listener: handleNoTypeArguments(()
+                              parseArgumentsOpt(late)
+                                parseArguments(late)
+                                  parseArgumentsRest(()
+                                    listener: beginArguments(()
+                                    listener: endArguments(0, (, ))
+                              listener: handleSend(late, ;)
+                        listener: endBinaryExpression(.)
+                    ensureSemicolon())
+                    listener: handleExpressionStatement(;)
+          notEofOrValue(}, new)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclaration(;, false)
+                parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+                  looksLikeLocalFunction(new)
+                  parseExpressionStatement(;)
+                    parseExpression(;)
+                      parsePrecedenceExpression(;, 1, true)
+                        parseUnaryExpression(;, true)
+                          parsePrimary(;, expression)
+                            parseNewExpression(;)
+                              listener: beginNewExpression(new)
+                              parseConstructorReference(new, null)
+                                ensureIdentifier(new, constructorReference)
+                                  listener: handleIdentifier(Y, constructorReference)
+                                listener: beginConstructorReference(Y)
+                                parseQualifiedRestOpt(Y, constructorReferenceContinuation)
+                                listener: handleNoTypeArguments(()
+                                listener: handleNoConstructorReferenceContinuationAfterTypeArguments(()
+                                listener: endConstructorReference(Y, null, ()
+                              parseConstructorInvocationArguments(Y)
+                                parseArgumentsRest(()
+                                  listener: beginArguments(()
+                                  listener: endArguments(0, (, ))
+                              listener: endNewExpression(new)
+                        parsePrimary(., expressionContinuation)
+                          inPlainSync()
+                          parseSendOrFunctionLiteral(., expressionContinuation)
+                            parseSend(., expressionContinuation)
+                              ensureIdentifier(., expressionContinuation)
+                                inPlainSync()
+                                listener: handleIdentifier(late, expressionContinuation)
+                              listener: handleNoTypeArguments(;)
+                              parseArgumentsOpt(late)
+                                listener: handleNoArguments(;)
+                              listener: handleSend(late, ;)
+                        listener: endBinaryExpression(.)
+                    ensureSemicolon(late)
+                    listener: handleExpressionStatement(;)
+          notEofOrValue(}, late)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclaration(;, false)
+                parseExpressionStatementOrDeclarationAfterModifiers(late, ;, late, null, null, false)
+                  looksLikeLocalFunction(foo)
+                  listener: beginMetadataStar(late)
+                  listener: endMetadataStar(0)
+                  listener: handleIdentifier(int, typeReference)
+                  listener: handleNoTypeArguments(foo)
+                  listener: handleType(int, null)
+                  listener: beginVariablesDeclaration(foo, late, null)
+                  parseVariablesDeclarationRest(int, true)
+                    parseOptionallyInitializedIdentifier(int)
+                      ensureIdentifier(int, localVariableDeclaration)
+                        listener: handleIdentifier(foo, localVariableDeclaration)
+                      listener: beginInitializedIdentifier(foo)
+                      parseVariableInitializerOpt(foo)
+                        listener: handleNoVariableInitializer(;)
+                      listener: endInitializedIdentifier(foo)
+                    ensureSemicolon(foo)
+                    listener: endVariablesDeclaration(1, ;)
+          notEofOrValue(}, foo)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+                looksLikeLocalFunction(foo)
+                parseExpressionStatement(;)
+                  parseExpression(;)
+                    parsePrecedenceExpression(;, 1, true)
+                      parseUnaryExpression(;, true)
+                        parsePrimary(;, expression)
+                          parseSendOrFunctionLiteral(;, expression)
+                            parseSend(;, expression)
+                              ensureIdentifier(;, expression)
+                                listener: handleIdentifier(foo, expression)
+                              listener: handleNoTypeArguments(=)
+                              parseArgumentsOpt(foo)
+                                listener: handleNoArguments(=)
+                              listener: handleSend(foo, =)
+                      parsePrecedenceExpression(=, 1, true)
+                        parseUnaryExpression(=, true)
+                          parsePrimary(=, expression)
+                            parseLiteralInt(=)
+                              listener: handleLiteralInt(42)
+                      listener: handleAssignmentExpression(=)
+                  ensureSemicolon(42)
+                  listener: handleExpressionStatement(;)
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(8, {, })
+        listener: endTopLevelMethod(main, null, })
+  listener: endTopLevelDeclaration(late)
+  parseTopLevelDeclarationImpl(}, Instance of 'DirectiveContext')
+    parseMetadataStar(})
+      listener: beginMetadataStar(late)
+      listener: endMetadataStar(0)
+    parseTopLevelMemberImpl(})
+      listener: beginTopLevelMember(late)
+      parseTopLevelMethod(}, null, }, Instance of 'NoType', null, late)
+        listener: beginTopLevelMethod(}, null)
+        listener: handleNoType(})
+        ensureIdentifier(}, topLevelFunctionDeclaration)
+          listener: handleIdentifier(late, topLevelFunctionDeclaration)
+        parseMethodTypeVar(late)
+          listener: handleNoTypeVariables(()
+        parseGetterOrFormalParameters(late, late, false, MemberKind.TopLevelMethod)
+          parseFormalParameters(late, 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(}, print)
+          parseStatement({)
+            parseStatementX({)
+              parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+                looksLikeLocalFunction(print)
+                parseExpressionStatement({)
+                  parseExpression({)
+                    parsePrecedenceExpression({, 1, true)
+                      parseUnaryExpression({, true)
+                        parsePrimary({, expression)
+                          parseSendOrFunctionLiteral({, expression)
+                            looksLikeFunctionBody(;)
+                            parseSend({, expression)
+                              ensureIdentifier({, expression)
+                                listener: handleIdentifier(print, expression)
+                              listener: handleNoTypeArguments(()
+                              parseArgumentsOpt(print)
+                                parseArguments(print)
+                                  parseArgumentsRest(()
+                                    listener: beginArguments(()
+                                    parseExpression(()
+                                      parsePrecedenceExpression((, 1, true)
+                                        parseUnaryExpression((, true)
+                                          parsePrimary((, expression)
+                                            parseLiteralString(()
+                                              parseSingleLiteralString(()
+                                                listener: beginLiteralString("hello")
+                                                listener: endLiteralString(0, ))
+                                    listener: endArguments(1, (, ))
+                              listener: handleSend(print, ;)
+                  ensureSemicolon())
+                  listener: handleExpressionStatement(;)
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(1, {, })
+        listener: endTopLevelMethod(late, null, })
+  listener: endTopLevelDeclaration(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(X, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, X)
+        parseClass(X, class, class, X)
+          parseClassHeaderOpt(X, class, class)
+            parseClassExtendsOpt(X)
+              listener: handleNoType(X)
+              listener: handleClassExtends(null)
+            parseWithClauseOpt(X)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(X)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(X, DeclarationKind.Class, X)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, late)
+            parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, X)
+              parseMetadataStar({)
+                listener: beginMetadataStar(late)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              parseMethod({, null, null, null, null, null, {, Instance of 'NoType', null, late, DeclarationKind.Class, X)
+                listener: beginMethod(null, null, null, null, null, late)
+                listener: handleNoType({)
+                ensureIdentifier({, methodDeclaration)
+                  listener: handleIdentifier(late, methodDeclaration)
+                parseQualifiedRestOpt(late, methodDeclarationContinuation)
+                parseMethodTypeVar(late)
+                  listener: handleNoTypeVariables(()
+                parseGetterOrFormalParameters(late, late, false, MemberKind.NonStaticMethod)
+                  parseFormalParameters(late, MemberKind.NonStaticMethod)
+                    parseFormalParametersRest((, MemberKind.NonStaticMethod)
+                      listener: beginFormalParameters((, MemberKind.NonStaticMethod)
+                      listener: endFormalParameters(0, (, ), MemberKind.NonStaticMethod)
+                parseInitializersOpt())
+                  listener: handleNoInitializers()
+                parseAsyncModifierOpt())
+                  listener: handleAsyncModifier(null, null)
+                  inPlainSync()
+                inPlainSync()
+                parseFunctionBody(), false, true)
+                  listener: beginBlockFunctionBody({)
+                  notEofOrValue(}, print)
+                  parseStatement({)
+                    parseStatementX({)
+                      parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+                        looksLikeLocalFunction(print)
+                        parseExpressionStatement({)
+                          parseExpression({)
+                            parsePrecedenceExpression({, 1, true)
+                              parseUnaryExpression({, true)
+                                parsePrimary({, expression)
+                                  parseSendOrFunctionLiteral({, expression)
+                                    looksLikeFunctionBody(;)
+                                    parseSend({, expression)
+                                      ensureIdentifier({, expression)
+                                        listener: handleIdentifier(print, expression)
+                                      listener: handleNoTypeArguments(()
+                                      parseArgumentsOpt(print)
+                                        parseArguments(print)
+                                          parseArgumentsRest(()
+                                            listener: beginArguments(()
+                                            parseExpression(()
+                                              parsePrecedenceExpression((, 1, true)
+                                                parseUnaryExpression((, true)
+                                                  parsePrimary((, expression)
+                                                    parseLiteralString(()
+                                                      parseSingleLiteralString(()
+                                                        listener: beginLiteralString("hello")
+                                                        listener: endLiteralString(0, ))
+                                            listener: endArguments(1, (, ))
+                                      listener: handleSend(print, ;)
+                          ensureSemicolon())
+                          listener: handleExpressionStatement(;)
+                  notEofOrValue(}, })
+                  listener: endBlockFunctionBody(1, {, })
+                listener: endClassMethod(null, late, (, null, })
+              listener: endMember()
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration(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(Y, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, Y)
+        parseClass(Y, class, class, Y)
+          parseClassHeaderOpt(Y, class, class)
+            parseClassExtendsOpt(Y)
+              listener: handleNoType(Y)
+              listener: handleClassExtends(null)
+            parseWithClauseOpt(Y)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(Y)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(Y, DeclarationKind.Class, Y)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, int)
+            parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, Y)
+              parseMetadataStar({)
+                listener: beginMetadataStar(int)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              parseFields({, null, null, null, null, null, {, Instance of 'SimpleType', late, DeclarationKind.Class)
+                listener: handleIdentifier(int, typeReference)
+                listener: handleNoTypeArguments(late)
+                listener: handleType(int, null)
+                ensureIdentifier(int, fieldDeclaration)
+                  listener: handleIdentifier(late, fieldDeclaration)
+                parseFieldInitializerOpt(late, late, null, null, DeclarationKind.Class)
+                  listener: beginFieldInitializer(=)
+                  parseExpression(=)
+                    parsePrecedenceExpression(=, 1, true)
+                      parseUnaryExpression(=, true)
+                        parsePrimary(=, expression)
+                          parseLiteralInt(=)
+                            listener: handleLiteralInt(42)
+                  listener: endFieldInitializer(=, ;)
+                listener: endClassFields(null, null, null, null, 1, int, ;)
+              listener: endMember()
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(main)
+  listener: endCompilationUnit(4, )
diff --git a/pkg/front_end/parser_testcases/nnbd/required_member.dart b/pkg/front_end/parser_testcases/nnbd/required_member.dart
new file mode 100644
index 0000000..634d956
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/required_member.dart
@@ -0,0 +1,22 @@
+main() {
+  dynamic foo = new X();
+  var bar = foo.required;
+  required();
+  bar();
+  new X().required();
+  new Y().required;
+}
+
+required() {
+  print("hello");
+}
+
+class X {
+  required() {
+    print("hello");
+  }
+}
+
+class Y {
+  int required = 42;
+}
diff --git a/pkg/front_end/parser_testcases/nnbd/required_member.dart.expect b/pkg/front_end/parser_testcases/nnbd/required_member.dart.expect
new file mode 100644
index 0000000..719aa15
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/required_member.dart.expect
@@ -0,0 +1,186 @@
+beginCompilationUnit(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(dynamic)
+        endMetadataStar(0)
+        handleIdentifier(dynamic, typeReference)
+        handleNoTypeArguments(foo)
+        handleType(dynamic, null)
+        beginVariablesDeclaration(foo, null, null)
+          handleIdentifier(foo, localVariableDeclaration)
+          beginInitializedIdentifier(foo)
+            beginVariableInitializer(=)
+              beginNewExpression(new)
+                handleIdentifier(X, constructorReference)
+                beginConstructorReference(X)
+                  handleNoTypeArguments(()
+                  handleNoConstructorReferenceContinuationAfterTypeArguments(()
+                endConstructorReference(X, null, ()
+                beginArguments(()
+                endArguments(0, (, ))
+              endNewExpression(new)
+            endVariableInitializer(=)
+          endInitializedIdentifier(foo)
+        endVariablesDeclaration(1, ;)
+        beginMetadataStar(var)
+        endMetadataStar(0)
+        handleNoType(var)
+        beginVariablesDeclaration(bar, null, var)
+          handleIdentifier(bar, localVariableDeclaration)
+          beginInitializedIdentifier(bar)
+            beginVariableInitializer(=)
+              handleIdentifier(foo, expression)
+              handleNoTypeArguments(.)
+              handleNoArguments(.)
+              handleSend(foo, .)
+              handleIdentifier(required, expressionContinuation)
+              handleNoTypeArguments(;)
+              handleNoArguments(;)
+              handleSend(required, ;)
+            endBinaryExpression(.)
+          endVariableInitializer(=)
+        endInitializedIdentifier(bar)
+      endVariablesDeclaration(1, ;)
+      handleIdentifier(required, expression)
+      handleNoTypeArguments(()
+      beginArguments(()
+      endArguments(0, (, ))
+      handleSend(required, ;)
+      handleExpressionStatement(;)
+      handleIdentifier(bar, expression)
+      handleNoTypeArguments(()
+      beginArguments(()
+      endArguments(0, (, ))
+      handleSend(bar, ;)
+      handleExpressionStatement(;)
+      beginNewExpression(new)
+        handleIdentifier(X, constructorReference)
+        beginConstructorReference(X)
+          handleNoTypeArguments(()
+          handleNoConstructorReferenceContinuationAfterTypeArguments(()
+        endConstructorReference(X, null, ()
+        beginArguments(()
+        endArguments(0, (, ))
+      endNewExpression(new)
+      handleIdentifier(required, expressionContinuation)
+      handleNoTypeArguments(()
+      beginArguments(()
+      endArguments(0, (, ))
+      handleSend(required, ;)
+    endBinaryExpression(.)
+    handleExpressionStatement(;)
+    beginNewExpression(new)
+      handleIdentifier(Y, constructorReference)
+      beginConstructorReference(Y)
+        handleNoTypeArguments(()
+        handleNoConstructorReferenceContinuationAfterTypeArguments(()
+      endConstructorReference(Y, null, ()
+      beginArguments(()
+      endArguments(0, (, ))
+    endNewExpression(new)
+    handleIdentifier(required, expressionContinuation)
+    handleNoTypeArguments(;)
+    handleNoArguments(;)
+    handleSend(required, ;)
+  endBinaryExpression(.)
+  handleExpressionStatement(;)
+endBlockFunctionBody(6, {, })
+endTopLevelMethod(main, null, })
+endTopLevelDeclaration(required)
+beginMetadataStar(required)
+endMetadataStar(0)
+beginTopLevelMember(required)
+beginTopLevelMethod(}, null)
+handleNoType(})
+handleIdentifier(required, topLevelFunctionDeclaration)
+handleNoTypeVariables(()
+beginFormalParameters((, MemberKind.TopLevelMethod)
+endFormalParameters(0, (, ), MemberKind.TopLevelMethod)
+handleAsyncModifier(null, null)
+beginBlockFunctionBody({)
+  handleIdentifier(print, expression)
+  handleNoTypeArguments(()
+  beginArguments(()
+    beginLiteralString("hello")
+    endLiteralString(0, ))
+  endArguments(1, (, ))
+  handleSend(print, ;)
+  handleExpressionStatement(;)
+endBlockFunctionBody(1, {, })
+endTopLevelMethod(required, null, })
+endTopLevelDeclaration(class)
+beginMetadataStar(class)
+endMetadataStar(0)
+beginClassOrNamedMixinApplicationPrelude(class)
+handleIdentifier(X, classOrMixinDeclaration)
+handleNoTypeVariables({)
+beginClassDeclaration(class, null, X)
+handleNoType(X)
+handleClassExtends(null)
+handleClassNoWithClause()
+handleClassOrMixinImplements(null, 0)
+handleClassHeader(class, class, null)
+beginClassOrMixinBody(DeclarationKind.Class, {)
+  beginMetadataStar(required)
+  endMetadataStar(0)
+  beginMember()
+    beginMethod(null, null, null, null, null, required)
+      handleNoType({)
+      handleIdentifier(required, methodDeclaration)
+      handleNoTypeVariables(()
+      beginFormalParameters((, MemberKind.NonStaticMethod)
+      endFormalParameters(0, (, ), MemberKind.NonStaticMethod)
+      handleNoInitializers()
+      handleAsyncModifier(null, null)
+      beginBlockFunctionBody({)
+        handleIdentifier(print, expression)
+        handleNoTypeArguments(()
+        beginArguments(()
+          beginLiteralString("hello")
+          endLiteralString(0, ))
+        endArguments(1, (, ))
+        handleSend(print, ;)
+        handleExpressionStatement(;)
+      endBlockFunctionBody(1, {, })
+    endClassMethod(null, required, (, null, })
+  endMember()
+endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+endClassDeclaration(class, })
+endTopLevelDeclaration(class)
+beginMetadataStar(class)
+endMetadataStar(0)
+beginClassOrNamedMixinApplicationPrelude(class)
+handleIdentifier(Y, classOrMixinDeclaration)
+handleNoTypeVariables({)
+beginClassDeclaration(class, null, Y)
+handleNoType(Y)
+handleClassExtends(null)
+handleClassNoWithClause()
+handleClassOrMixinImplements(null, 0)
+handleClassHeader(class, class, null)
+beginClassOrMixinBody(DeclarationKind.Class, {)
+  beginMetadataStar(int)
+  endMetadataStar(0)
+  beginMember()
+    handleIdentifier(int, typeReference)
+    handleNoTypeArguments(required)
+    handleType(int, null)
+    handleIdentifier(required, fieldDeclaration)
+    beginFieldInitializer(=)
+      handleLiteralInt(42)
+    endFieldInitializer(=, ;)
+  endClassFields(null, null, null, null, 1, int, ;)
+endMember()
+endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+endClassDeclaration(class, })
+endTopLevelDeclaration()
+endCompilationUnit(4, )
diff --git a/pkg/front_end/parser_testcases/nnbd/required_member.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/required_member.dart.intertwined.expect
new file mode 100644
index 0000000..37936b9
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/required_member.dart.intertwined.expect
@@ -0,0 +1,455 @@
+parseUnit(main)
+  skipErrorTokens(main)
+  listener: beginCompilationUnit(main)
+  syntheticPreviousToken(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(}, dynamic)
+          parseStatement({)
+            parseStatementX({)
+              parseExpressionStatementOrDeclaration({, false)
+                parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+                  looksLikeLocalFunction(foo)
+                  listener: beginMetadataStar(dynamic)
+                  listener: endMetadataStar(0)
+                  listener: handleIdentifier(dynamic, typeReference)
+                  listener: handleNoTypeArguments(foo)
+                  listener: handleType(dynamic, null)
+                  listener: beginVariablesDeclaration(foo, null, null)
+                  parseVariablesDeclarationRest(dynamic, true)
+                    parseOptionallyInitializedIdentifier(dynamic)
+                      ensureIdentifier(dynamic, localVariableDeclaration)
+                        listener: handleIdentifier(foo, localVariableDeclaration)
+                      listener: beginInitializedIdentifier(foo)
+                      parseVariableInitializerOpt(foo)
+                        listener: beginVariableInitializer(=)
+                        parseExpression(=)
+                          parsePrecedenceExpression(=, 1, true)
+                            parseUnaryExpression(=, true)
+                              parsePrimary(=, expression)
+                                parseNewExpression(=)
+                                  listener: beginNewExpression(new)
+                                  parseConstructorReference(new, null)
+                                    ensureIdentifier(new, constructorReference)
+                                      listener: handleIdentifier(X, constructorReference)
+                                    listener: beginConstructorReference(X)
+                                    parseQualifiedRestOpt(X, constructorReferenceContinuation)
+                                    listener: handleNoTypeArguments(()
+                                    listener: handleNoConstructorReferenceContinuationAfterTypeArguments(()
+                                    listener: endConstructorReference(X, null, ()
+                                  parseConstructorInvocationArguments(X)
+                                    parseArgumentsRest(()
+                                      listener: beginArguments(()
+                                      listener: endArguments(0, (, ))
+                                  listener: endNewExpression(new)
+                        listener: endVariableInitializer(=)
+                      listener: endInitializedIdentifier(foo)
+                    ensureSemicolon())
+                    listener: endVariablesDeclaration(1, ;)
+          notEofOrValue(}, var)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclarationAfterModifiers(var, ;, null, var, null, false)
+                looksLikeLocalFunction(bar)
+                listener: beginMetadataStar(var)
+                listener: endMetadataStar(0)
+                listener: handleNoType(var)
+                listener: beginVariablesDeclaration(bar, null, var)
+                parseVariablesDeclarationRest(var, true)
+                  parseOptionallyInitializedIdentifier(var)
+                    ensureIdentifier(var, localVariableDeclaration)
+                      listener: handleIdentifier(bar, localVariableDeclaration)
+                    listener: beginInitializedIdentifier(bar)
+                    parseVariableInitializerOpt(bar)
+                      listener: beginVariableInitializer(=)
+                      parseExpression(=)
+                        parsePrecedenceExpression(=, 1, true)
+                          parseUnaryExpression(=, true)
+                            parsePrimary(=, expression)
+                              parseSendOrFunctionLiteral(=, expression)
+                                parseSend(=, expression)
+                                  ensureIdentifier(=, expression)
+                                    listener: handleIdentifier(foo, expression)
+                                  listener: handleNoTypeArguments(.)
+                                  parseArgumentsOpt(foo)
+                                    listener: handleNoArguments(.)
+                                  listener: handleSend(foo, .)
+                          parsePrimary(., expressionContinuation)
+                            inPlainSync()
+                            parseSendOrFunctionLiteral(., expressionContinuation)
+                              parseSend(., expressionContinuation)
+                                ensureIdentifier(., expressionContinuation)
+                                  inPlainSync()
+                                  listener: handleIdentifier(required, expressionContinuation)
+                                listener: handleNoTypeArguments(;)
+                                parseArgumentsOpt(required)
+                                  listener: handleNoArguments(;)
+                                listener: handleSend(required, ;)
+                          listener: endBinaryExpression(.)
+                      listener: endVariableInitializer(=)
+                    listener: endInitializedIdentifier(bar)
+                  ensureSemicolon(required)
+                  listener: endVariablesDeclaration(1, ;)
+          notEofOrValue(}, required)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclaration(;, false)
+                parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+                  looksLikeLocalFunction(required)
+                  parseExpressionStatement(;)
+                    parseExpression(;)
+                      parsePrecedenceExpression(;, 1, true)
+                        parseUnaryExpression(;, true)
+                          parsePrimary(;, expression)
+                            inPlainSync()
+                            parseSendOrFunctionLiteral(;, expression)
+                              looksLikeFunctionBody(;)
+                              parseSend(;, expression)
+                                ensureIdentifier(;, expression)
+                                  inPlainSync()
+                                  listener: handleIdentifier(required, expression)
+                                listener: handleNoTypeArguments(()
+                                parseArgumentsOpt(required)
+                                  parseArguments(required)
+                                    parseArgumentsRest(()
+                                      listener: beginArguments(()
+                                      listener: endArguments(0, (, ))
+                                listener: handleSend(required, ;)
+                    ensureSemicolon())
+                    listener: handleExpressionStatement(;)
+          notEofOrValue(}, bar)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+                looksLikeLocalFunction(bar)
+                parseExpressionStatement(;)
+                  parseExpression(;)
+                    parsePrecedenceExpression(;, 1, true)
+                      parseUnaryExpression(;, true)
+                        parsePrimary(;, expression)
+                          parseSendOrFunctionLiteral(;, expression)
+                            looksLikeFunctionBody(;)
+                            parseSend(;, expression)
+                              ensureIdentifier(;, expression)
+                                listener: handleIdentifier(bar, expression)
+                              listener: handleNoTypeArguments(()
+                              parseArgumentsOpt(bar)
+                                parseArguments(bar)
+                                  parseArgumentsRest(()
+                                    listener: beginArguments(()
+                                    listener: endArguments(0, (, ))
+                              listener: handleSend(bar, ;)
+                  ensureSemicolon())
+                  listener: handleExpressionStatement(;)
+          notEofOrValue(}, new)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclaration(;, false)
+                parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+                  looksLikeLocalFunction(new)
+                  parseExpressionStatement(;)
+                    parseExpression(;)
+                      parsePrecedenceExpression(;, 1, true)
+                        parseUnaryExpression(;, true)
+                          parsePrimary(;, expression)
+                            parseNewExpression(;)
+                              listener: beginNewExpression(new)
+                              parseConstructorReference(new, null)
+                                ensureIdentifier(new, constructorReference)
+                                  listener: handleIdentifier(X, constructorReference)
+                                listener: beginConstructorReference(X)
+                                parseQualifiedRestOpt(X, constructorReferenceContinuation)
+                                listener: handleNoTypeArguments(()
+                                listener: handleNoConstructorReferenceContinuationAfterTypeArguments(()
+                                listener: endConstructorReference(X, null, ()
+                              parseConstructorInvocationArguments(X)
+                                parseArgumentsRest(()
+                                  listener: beginArguments(()
+                                  listener: endArguments(0, (, ))
+                              listener: endNewExpression(new)
+                        parsePrimary(., expressionContinuation)
+                          inPlainSync()
+                          parseSendOrFunctionLiteral(., expressionContinuation)
+                            looksLikeFunctionBody(;)
+                            parseSend(., expressionContinuation)
+                              ensureIdentifier(., expressionContinuation)
+                                inPlainSync()
+                                listener: handleIdentifier(required, expressionContinuation)
+                              listener: handleNoTypeArguments(()
+                              parseArgumentsOpt(required)
+                                parseArguments(required)
+                                  parseArgumentsRest(()
+                                    listener: beginArguments(()
+                                    listener: endArguments(0, (, ))
+                              listener: handleSend(required, ;)
+                        listener: endBinaryExpression(.)
+                    ensureSemicolon())
+                    listener: handleExpressionStatement(;)
+          notEofOrValue(}, new)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclaration(;, false)
+                parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+                  looksLikeLocalFunction(new)
+                  parseExpressionStatement(;)
+                    parseExpression(;)
+                      parsePrecedenceExpression(;, 1, true)
+                        parseUnaryExpression(;, true)
+                          parsePrimary(;, expression)
+                            parseNewExpression(;)
+                              listener: beginNewExpression(new)
+                              parseConstructorReference(new, null)
+                                ensureIdentifier(new, constructorReference)
+                                  listener: handleIdentifier(Y, constructorReference)
+                                listener: beginConstructorReference(Y)
+                                parseQualifiedRestOpt(Y, constructorReferenceContinuation)
+                                listener: handleNoTypeArguments(()
+                                listener: handleNoConstructorReferenceContinuationAfterTypeArguments(()
+                                listener: endConstructorReference(Y, null, ()
+                              parseConstructorInvocationArguments(Y)
+                                parseArgumentsRest(()
+                                  listener: beginArguments(()
+                                  listener: endArguments(0, (, ))
+                              listener: endNewExpression(new)
+                        parsePrimary(., expressionContinuation)
+                          inPlainSync()
+                          parseSendOrFunctionLiteral(., expressionContinuation)
+                            parseSend(., expressionContinuation)
+                              ensureIdentifier(., expressionContinuation)
+                                inPlainSync()
+                                listener: handleIdentifier(required, expressionContinuation)
+                              listener: handleNoTypeArguments(;)
+                              parseArgumentsOpt(required)
+                                listener: handleNoArguments(;)
+                              listener: handleSend(required, ;)
+                        listener: endBinaryExpression(.)
+                    ensureSemicolon(required)
+                    listener: handleExpressionStatement(;)
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(6, {, })
+        listener: endTopLevelMethod(main, null, })
+  listener: endTopLevelDeclaration(required)
+  parseTopLevelDeclarationImpl(}, Instance of 'DirectiveContext')
+    parseMetadataStar(})
+      listener: beginMetadataStar(required)
+      listener: endMetadataStar(0)
+    parseTopLevelMemberImpl(})
+      listener: beginTopLevelMember(required)
+      parseTopLevelMethod(}, null, }, Instance of 'NoType', null, required)
+        listener: beginTopLevelMethod(}, null)
+        listener: handleNoType(})
+        ensureIdentifier(}, topLevelFunctionDeclaration)
+          listener: handleIdentifier(required, topLevelFunctionDeclaration)
+        parseMethodTypeVar(required)
+          listener: handleNoTypeVariables(()
+        parseGetterOrFormalParameters(required, required, false, MemberKind.TopLevelMethod)
+          parseFormalParameters(required, 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(}, print)
+          parseStatement({)
+            parseStatementX({)
+              parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+                looksLikeLocalFunction(print)
+                parseExpressionStatement({)
+                  parseExpression({)
+                    parsePrecedenceExpression({, 1, true)
+                      parseUnaryExpression({, true)
+                        parsePrimary({, expression)
+                          parseSendOrFunctionLiteral({, expression)
+                            looksLikeFunctionBody(;)
+                            parseSend({, expression)
+                              ensureIdentifier({, expression)
+                                listener: handleIdentifier(print, expression)
+                              listener: handleNoTypeArguments(()
+                              parseArgumentsOpt(print)
+                                parseArguments(print)
+                                  parseArgumentsRest(()
+                                    listener: beginArguments(()
+                                    parseExpression(()
+                                      parsePrecedenceExpression((, 1, true)
+                                        parseUnaryExpression((, true)
+                                          parsePrimary((, expression)
+                                            parseLiteralString(()
+                                              parseSingleLiteralString(()
+                                                listener: beginLiteralString("hello")
+                                                listener: endLiteralString(0, ))
+                                    listener: endArguments(1, (, ))
+                              listener: handleSend(print, ;)
+                  ensureSemicolon())
+                  listener: handleExpressionStatement(;)
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(1, {, })
+        listener: endTopLevelMethod(required, null, })
+  listener: endTopLevelDeclaration(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(X, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, X)
+        parseClass(X, class, class, X)
+          parseClassHeaderOpt(X, class, class)
+            parseClassExtendsOpt(X)
+              listener: handleNoType(X)
+              listener: handleClassExtends(null)
+            parseWithClauseOpt(X)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(X)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(X, DeclarationKind.Class, X)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, required)
+            parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, X)
+              parseMetadataStar({)
+                listener: beginMetadataStar(required)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              parseMethod({, null, null, null, null, null, {, Instance of 'NoType', null, required, DeclarationKind.Class, X)
+                listener: beginMethod(null, null, null, null, null, required)
+                listener: handleNoType({)
+                ensureIdentifier({, methodDeclaration)
+                  listener: handleIdentifier(required, methodDeclaration)
+                parseQualifiedRestOpt(required, methodDeclarationContinuation)
+                parseMethodTypeVar(required)
+                  listener: handleNoTypeVariables(()
+                parseGetterOrFormalParameters(required, required, false, MemberKind.NonStaticMethod)
+                  parseFormalParameters(required, MemberKind.NonStaticMethod)
+                    parseFormalParametersRest((, MemberKind.NonStaticMethod)
+                      listener: beginFormalParameters((, MemberKind.NonStaticMethod)
+                      listener: endFormalParameters(0, (, ), MemberKind.NonStaticMethod)
+                parseInitializersOpt())
+                  listener: handleNoInitializers()
+                parseAsyncModifierOpt())
+                  listener: handleAsyncModifier(null, null)
+                  inPlainSync()
+                inPlainSync()
+                parseFunctionBody(), false, true)
+                  listener: beginBlockFunctionBody({)
+                  notEofOrValue(}, print)
+                  parseStatement({)
+                    parseStatementX({)
+                      parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+                        looksLikeLocalFunction(print)
+                        parseExpressionStatement({)
+                          parseExpression({)
+                            parsePrecedenceExpression({, 1, true)
+                              parseUnaryExpression({, true)
+                                parsePrimary({, expression)
+                                  parseSendOrFunctionLiteral({, expression)
+                                    looksLikeFunctionBody(;)
+                                    parseSend({, expression)
+                                      ensureIdentifier({, expression)
+                                        listener: handleIdentifier(print, expression)
+                                      listener: handleNoTypeArguments(()
+                                      parseArgumentsOpt(print)
+                                        parseArguments(print)
+                                          parseArgumentsRest(()
+                                            listener: beginArguments(()
+                                            parseExpression(()
+                                              parsePrecedenceExpression((, 1, true)
+                                                parseUnaryExpression((, true)
+                                                  parsePrimary((, expression)
+                                                    parseLiteralString(()
+                                                      parseSingleLiteralString(()
+                                                        listener: beginLiteralString("hello")
+                                                        listener: endLiteralString(0, ))
+                                            listener: endArguments(1, (, ))
+                                      listener: handleSend(print, ;)
+                          ensureSemicolon())
+                          listener: handleExpressionStatement(;)
+                  notEofOrValue(}, })
+                  listener: endBlockFunctionBody(1, {, })
+                listener: endClassMethod(null, required, (, null, })
+              listener: endMember()
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration(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(Y, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, Y)
+        parseClass(Y, class, class, Y)
+          parseClassHeaderOpt(Y, class, class)
+            parseClassExtendsOpt(Y)
+              listener: handleNoType(Y)
+              listener: handleClassExtends(null)
+            parseWithClauseOpt(Y)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(Y)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(Y, DeclarationKind.Class, Y)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, int)
+            parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, Y)
+              parseMetadataStar({)
+                listener: beginMetadataStar(int)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              parseFields({, null, null, null, null, null, {, Instance of 'SimpleType', required, DeclarationKind.Class)
+                listener: handleIdentifier(int, typeReference)
+                listener: handleNoTypeArguments(required)
+                listener: handleType(int, null)
+                ensureIdentifier(int, fieldDeclaration)
+                  listener: handleIdentifier(required, fieldDeclaration)
+                parseFieldInitializerOpt(required, required, null, null, DeclarationKind.Class)
+                  listener: beginFieldInitializer(=)
+                  parseExpression(=)
+                    parsePrecedenceExpression(=, 1, true)
+                      parseUnaryExpression(=, true)
+                        parsePrimary(=, expression)
+                          parseLiteralInt(=)
+                            listener: handleLiteralInt(42)
+                  listener: endFieldInitializer(=, ;)
+                listener: endClassFields(null, null, null, null, 1, int, ;)
+              listener: endMember()
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(main)
+  listener: endCompilationUnit(4, )
diff --git a/pkg/front_end/parser_testcases/nnbd/required_modifier.dart b/pkg/front_end/parser_testcases/nnbd/required_modifier.dart
new file mode 100644
index 0000000..5c2b38e
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/required_modifier.dart
@@ -0,0 +1,22 @@
+main() {
+  dynamic foo = new X();
+  var bar = foo.required;
+  required();
+  bar();
+  new X().required();
+  new Y().required;
+}
+
+required({required int named}) {
+  print("hello");
+}
+
+class X {
+  required() {
+    print("hello");
+  }
+}
+
+class Y {
+  int required = 42;
+}
diff --git a/pkg/front_end/parser_testcases/nnbd/required_modifier.dart.expect b/pkg/front_end/parser_testcases/nnbd/required_modifier.dart.expect
new file mode 100644
index 0000000..9df173c
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/required_modifier.dart.expect
@@ -0,0 +1,197 @@
+beginCompilationUnit(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(dynamic)
+        endMetadataStar(0)
+        handleIdentifier(dynamic, typeReference)
+        handleNoTypeArguments(foo)
+        handleType(dynamic, null)
+        beginVariablesDeclaration(foo, null, null)
+          handleIdentifier(foo, localVariableDeclaration)
+          beginInitializedIdentifier(foo)
+            beginVariableInitializer(=)
+              beginNewExpression(new)
+                handleIdentifier(X, constructorReference)
+                beginConstructorReference(X)
+                  handleNoTypeArguments(()
+                  handleNoConstructorReferenceContinuationAfterTypeArguments(()
+                endConstructorReference(X, null, ()
+                beginArguments(()
+                endArguments(0, (, ))
+              endNewExpression(new)
+            endVariableInitializer(=)
+          endInitializedIdentifier(foo)
+        endVariablesDeclaration(1, ;)
+        beginMetadataStar(var)
+        endMetadataStar(0)
+        handleNoType(var)
+        beginVariablesDeclaration(bar, null, var)
+          handleIdentifier(bar, localVariableDeclaration)
+          beginInitializedIdentifier(bar)
+            beginVariableInitializer(=)
+              handleIdentifier(foo, expression)
+              handleNoTypeArguments(.)
+              handleNoArguments(.)
+              handleSend(foo, .)
+              handleIdentifier(required, expressionContinuation)
+              handleNoTypeArguments(;)
+              handleNoArguments(;)
+              handleSend(required, ;)
+            endBinaryExpression(.)
+          endVariableInitializer(=)
+        endInitializedIdentifier(bar)
+      endVariablesDeclaration(1, ;)
+      handleIdentifier(required, expression)
+      handleNoTypeArguments(()
+      beginArguments(()
+      endArguments(0, (, ))
+      handleSend(required, ;)
+      handleExpressionStatement(;)
+      handleIdentifier(bar, expression)
+      handleNoTypeArguments(()
+      beginArguments(()
+      endArguments(0, (, ))
+      handleSend(bar, ;)
+      handleExpressionStatement(;)
+      beginNewExpression(new)
+        handleIdentifier(X, constructorReference)
+        beginConstructorReference(X)
+          handleNoTypeArguments(()
+          handleNoConstructorReferenceContinuationAfterTypeArguments(()
+        endConstructorReference(X, null, ()
+        beginArguments(()
+        endArguments(0, (, ))
+      endNewExpression(new)
+      handleIdentifier(required, expressionContinuation)
+      handleNoTypeArguments(()
+      beginArguments(()
+      endArguments(0, (, ))
+      handleSend(required, ;)
+    endBinaryExpression(.)
+    handleExpressionStatement(;)
+    beginNewExpression(new)
+      handleIdentifier(Y, constructorReference)
+      beginConstructorReference(Y)
+        handleNoTypeArguments(()
+        handleNoConstructorReferenceContinuationAfterTypeArguments(()
+      endConstructorReference(Y, null, ()
+      beginArguments(()
+      endArguments(0, (, ))
+    endNewExpression(new)
+    handleIdentifier(required, expressionContinuation)
+    handleNoTypeArguments(;)
+    handleNoArguments(;)
+    handleSend(required, ;)
+  endBinaryExpression(.)
+  handleExpressionStatement(;)
+endBlockFunctionBody(6, {, })
+endTopLevelMethod(main, null, })
+endTopLevelDeclaration(required)
+beginMetadataStar(required)
+endMetadataStar(0)
+beginTopLevelMember(required)
+beginTopLevelMethod(}, null)
+handleNoType(})
+handleIdentifier(required, topLevelFunctionDeclaration)
+handleNoTypeVariables(()
+beginFormalParameters((, MemberKind.TopLevelMethod)
+  beginOptionalFormalParameters({)
+    beginMetadataStar(required)
+    endMetadataStar(0)
+    beginFormalParameter(required, MemberKind.TopLevelMethod, required, null, null)
+      handleIdentifier(int, typeReference)
+      handleNoTypeArguments(named)
+      handleType(int, null)
+      handleIdentifier(named, formalParameterDeclaration)
+      handleFormalParameterWithoutValue(})
+    endFormalParameter(null, null, named, null, null, FormalParameterKind.optionalNamed, MemberKind.TopLevelMethod)
+  endOptionalFormalParameters(1, {, })
+endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+handleAsyncModifier(null, null)
+beginBlockFunctionBody({)
+  handleIdentifier(print, expression)
+  handleNoTypeArguments(()
+  beginArguments(()
+    beginLiteralString("hello")
+    endLiteralString(0, ))
+  endArguments(1, (, ))
+  handleSend(print, ;)
+  handleExpressionStatement(;)
+endBlockFunctionBody(1, {, })
+endTopLevelMethod(required, null, })
+endTopLevelDeclaration(class)
+beginMetadataStar(class)
+endMetadataStar(0)
+beginClassOrNamedMixinApplicationPrelude(class)
+handleIdentifier(X, classOrMixinDeclaration)
+handleNoTypeVariables({)
+beginClassDeclaration(class, null, X)
+handleNoType(X)
+handleClassExtends(null)
+handleClassNoWithClause()
+handleClassOrMixinImplements(null, 0)
+handleClassHeader(class, class, null)
+beginClassOrMixinBody(DeclarationKind.Class, {)
+  beginMetadataStar(required)
+  endMetadataStar(0)
+  beginMember()
+    beginMethod(null, null, null, null, null, required)
+      handleNoType({)
+      handleIdentifier(required, methodDeclaration)
+      handleNoTypeVariables(()
+      beginFormalParameters((, MemberKind.NonStaticMethod)
+      endFormalParameters(0, (, ), MemberKind.NonStaticMethod)
+      handleNoInitializers()
+      handleAsyncModifier(null, null)
+      beginBlockFunctionBody({)
+        handleIdentifier(print, expression)
+        handleNoTypeArguments(()
+        beginArguments(()
+          beginLiteralString("hello")
+          endLiteralString(0, ))
+        endArguments(1, (, ))
+        handleSend(print, ;)
+        handleExpressionStatement(;)
+      endBlockFunctionBody(1, {, })
+    endClassMethod(null, required, (, null, })
+  endMember()
+endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+endClassDeclaration(class, })
+endTopLevelDeclaration(class)
+beginMetadataStar(class)
+endMetadataStar(0)
+beginClassOrNamedMixinApplicationPrelude(class)
+handleIdentifier(Y, classOrMixinDeclaration)
+handleNoTypeVariables({)
+beginClassDeclaration(class, null, Y)
+handleNoType(Y)
+handleClassExtends(null)
+handleClassNoWithClause()
+handleClassOrMixinImplements(null, 0)
+handleClassHeader(class, class, null)
+beginClassOrMixinBody(DeclarationKind.Class, {)
+  beginMetadataStar(int)
+  endMetadataStar(0)
+  beginMember()
+    handleIdentifier(int, typeReference)
+    handleNoTypeArguments(required)
+    handleType(int, null)
+    handleIdentifier(required, fieldDeclaration)
+    beginFieldInitializer(=)
+      handleLiteralInt(42)
+    endFieldInitializer(=, ;)
+  endClassFields(null, null, null, null, 1, int, ;)
+endMember()
+endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+endClassDeclaration(class, })
+endTopLevelDeclaration()
+endCompilationUnit(4, )
diff --git a/pkg/front_end/parser_testcases/nnbd/required_modifier.dart.intertwined.expect b/pkg/front_end/parser_testcases/nnbd/required_modifier.dart.intertwined.expect
new file mode 100644
index 0000000..831a9fa
--- /dev/null
+++ b/pkg/front_end/parser_testcases/nnbd/required_modifier.dart.intertwined.expect
@@ -0,0 +1,471 @@
+parseUnit(main)
+  skipErrorTokens(main)
+  listener: beginCompilationUnit(main)
+  syntheticPreviousToken(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(}, dynamic)
+          parseStatement({)
+            parseStatementX({)
+              parseExpressionStatementOrDeclaration({, false)
+                parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+                  looksLikeLocalFunction(foo)
+                  listener: beginMetadataStar(dynamic)
+                  listener: endMetadataStar(0)
+                  listener: handleIdentifier(dynamic, typeReference)
+                  listener: handleNoTypeArguments(foo)
+                  listener: handleType(dynamic, null)
+                  listener: beginVariablesDeclaration(foo, null, null)
+                  parseVariablesDeclarationRest(dynamic, true)
+                    parseOptionallyInitializedIdentifier(dynamic)
+                      ensureIdentifier(dynamic, localVariableDeclaration)
+                        listener: handleIdentifier(foo, localVariableDeclaration)
+                      listener: beginInitializedIdentifier(foo)
+                      parseVariableInitializerOpt(foo)
+                        listener: beginVariableInitializer(=)
+                        parseExpression(=)
+                          parsePrecedenceExpression(=, 1, true)
+                            parseUnaryExpression(=, true)
+                              parsePrimary(=, expression)
+                                parseNewExpression(=)
+                                  listener: beginNewExpression(new)
+                                  parseConstructorReference(new, null)
+                                    ensureIdentifier(new, constructorReference)
+                                      listener: handleIdentifier(X, constructorReference)
+                                    listener: beginConstructorReference(X)
+                                    parseQualifiedRestOpt(X, constructorReferenceContinuation)
+                                    listener: handleNoTypeArguments(()
+                                    listener: handleNoConstructorReferenceContinuationAfterTypeArguments(()
+                                    listener: endConstructorReference(X, null, ()
+                                  parseConstructorInvocationArguments(X)
+                                    parseArgumentsRest(()
+                                      listener: beginArguments(()
+                                      listener: endArguments(0, (, ))
+                                  listener: endNewExpression(new)
+                        listener: endVariableInitializer(=)
+                      listener: endInitializedIdentifier(foo)
+                    ensureSemicolon())
+                    listener: endVariablesDeclaration(1, ;)
+          notEofOrValue(}, var)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclarationAfterModifiers(var, ;, null, var, null, false)
+                looksLikeLocalFunction(bar)
+                listener: beginMetadataStar(var)
+                listener: endMetadataStar(0)
+                listener: handleNoType(var)
+                listener: beginVariablesDeclaration(bar, null, var)
+                parseVariablesDeclarationRest(var, true)
+                  parseOptionallyInitializedIdentifier(var)
+                    ensureIdentifier(var, localVariableDeclaration)
+                      listener: handleIdentifier(bar, localVariableDeclaration)
+                    listener: beginInitializedIdentifier(bar)
+                    parseVariableInitializerOpt(bar)
+                      listener: beginVariableInitializer(=)
+                      parseExpression(=)
+                        parsePrecedenceExpression(=, 1, true)
+                          parseUnaryExpression(=, true)
+                            parsePrimary(=, expression)
+                              parseSendOrFunctionLiteral(=, expression)
+                                parseSend(=, expression)
+                                  ensureIdentifier(=, expression)
+                                    listener: handleIdentifier(foo, expression)
+                                  listener: handleNoTypeArguments(.)
+                                  parseArgumentsOpt(foo)
+                                    listener: handleNoArguments(.)
+                                  listener: handleSend(foo, .)
+                          parsePrimary(., expressionContinuation)
+                            inPlainSync()
+                            parseSendOrFunctionLiteral(., expressionContinuation)
+                              parseSend(., expressionContinuation)
+                                ensureIdentifier(., expressionContinuation)
+                                  inPlainSync()
+                                  listener: handleIdentifier(required, expressionContinuation)
+                                listener: handleNoTypeArguments(;)
+                                parseArgumentsOpt(required)
+                                  listener: handleNoArguments(;)
+                                listener: handleSend(required, ;)
+                          listener: endBinaryExpression(.)
+                      listener: endVariableInitializer(=)
+                    listener: endInitializedIdentifier(bar)
+                  ensureSemicolon(required)
+                  listener: endVariablesDeclaration(1, ;)
+          notEofOrValue(}, required)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclaration(;, false)
+                parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+                  looksLikeLocalFunction(required)
+                  parseExpressionStatement(;)
+                    parseExpression(;)
+                      parsePrecedenceExpression(;, 1, true)
+                        parseUnaryExpression(;, true)
+                          parsePrimary(;, expression)
+                            inPlainSync()
+                            parseSendOrFunctionLiteral(;, expression)
+                              looksLikeFunctionBody(;)
+                              parseSend(;, expression)
+                                ensureIdentifier(;, expression)
+                                  inPlainSync()
+                                  listener: handleIdentifier(required, expression)
+                                listener: handleNoTypeArguments(()
+                                parseArgumentsOpt(required)
+                                  parseArguments(required)
+                                    parseArgumentsRest(()
+                                      listener: beginArguments(()
+                                      listener: endArguments(0, (, ))
+                                listener: handleSend(required, ;)
+                    ensureSemicolon())
+                    listener: handleExpressionStatement(;)
+          notEofOrValue(}, bar)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+                looksLikeLocalFunction(bar)
+                parseExpressionStatement(;)
+                  parseExpression(;)
+                    parsePrecedenceExpression(;, 1, true)
+                      parseUnaryExpression(;, true)
+                        parsePrimary(;, expression)
+                          parseSendOrFunctionLiteral(;, expression)
+                            looksLikeFunctionBody(;)
+                            parseSend(;, expression)
+                              ensureIdentifier(;, expression)
+                                listener: handleIdentifier(bar, expression)
+                              listener: handleNoTypeArguments(()
+                              parseArgumentsOpt(bar)
+                                parseArguments(bar)
+                                  parseArgumentsRest(()
+                                    listener: beginArguments(()
+                                    listener: endArguments(0, (, ))
+                              listener: handleSend(bar, ;)
+                  ensureSemicolon())
+                  listener: handleExpressionStatement(;)
+          notEofOrValue(}, new)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclaration(;, false)
+                parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+                  looksLikeLocalFunction(new)
+                  parseExpressionStatement(;)
+                    parseExpression(;)
+                      parsePrecedenceExpression(;, 1, true)
+                        parseUnaryExpression(;, true)
+                          parsePrimary(;, expression)
+                            parseNewExpression(;)
+                              listener: beginNewExpression(new)
+                              parseConstructorReference(new, null)
+                                ensureIdentifier(new, constructorReference)
+                                  listener: handleIdentifier(X, constructorReference)
+                                listener: beginConstructorReference(X)
+                                parseQualifiedRestOpt(X, constructorReferenceContinuation)
+                                listener: handleNoTypeArguments(()
+                                listener: handleNoConstructorReferenceContinuationAfterTypeArguments(()
+                                listener: endConstructorReference(X, null, ()
+                              parseConstructorInvocationArguments(X)
+                                parseArgumentsRest(()
+                                  listener: beginArguments(()
+                                  listener: endArguments(0, (, ))
+                              listener: endNewExpression(new)
+                        parsePrimary(., expressionContinuation)
+                          inPlainSync()
+                          parseSendOrFunctionLiteral(., expressionContinuation)
+                            looksLikeFunctionBody(;)
+                            parseSend(., expressionContinuation)
+                              ensureIdentifier(., expressionContinuation)
+                                inPlainSync()
+                                listener: handleIdentifier(required, expressionContinuation)
+                              listener: handleNoTypeArguments(()
+                              parseArgumentsOpt(required)
+                                parseArguments(required)
+                                  parseArgumentsRest(()
+                                    listener: beginArguments(()
+                                    listener: endArguments(0, (, ))
+                              listener: handleSend(required, ;)
+                        listener: endBinaryExpression(.)
+                    ensureSemicolon())
+                    listener: handleExpressionStatement(;)
+          notEofOrValue(}, new)
+          parseStatement(;)
+            parseStatementX(;)
+              parseExpressionStatementOrDeclaration(;, false)
+                parseExpressionStatementOrDeclarationAfterModifiers(;, ;, null, null, null, false)
+                  looksLikeLocalFunction(new)
+                  parseExpressionStatement(;)
+                    parseExpression(;)
+                      parsePrecedenceExpression(;, 1, true)
+                        parseUnaryExpression(;, true)
+                          parsePrimary(;, expression)
+                            parseNewExpression(;)
+                              listener: beginNewExpression(new)
+                              parseConstructorReference(new, null)
+                                ensureIdentifier(new, constructorReference)
+                                  listener: handleIdentifier(Y, constructorReference)
+                                listener: beginConstructorReference(Y)
+                                parseQualifiedRestOpt(Y, constructorReferenceContinuation)
+                                listener: handleNoTypeArguments(()
+                                listener: handleNoConstructorReferenceContinuationAfterTypeArguments(()
+                                listener: endConstructorReference(Y, null, ()
+                              parseConstructorInvocationArguments(Y)
+                                parseArgumentsRest(()
+                                  listener: beginArguments(()
+                                  listener: endArguments(0, (, ))
+                              listener: endNewExpression(new)
+                        parsePrimary(., expressionContinuation)
+                          inPlainSync()
+                          parseSendOrFunctionLiteral(., expressionContinuation)
+                            parseSend(., expressionContinuation)
+                              ensureIdentifier(., expressionContinuation)
+                                inPlainSync()
+                                listener: handleIdentifier(required, expressionContinuation)
+                              listener: handleNoTypeArguments(;)
+                              parseArgumentsOpt(required)
+                                listener: handleNoArguments(;)
+                              listener: handleSend(required, ;)
+                        listener: endBinaryExpression(.)
+                    ensureSemicolon(required)
+                    listener: handleExpressionStatement(;)
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(6, {, })
+        listener: endTopLevelMethod(main, null, })
+  listener: endTopLevelDeclaration(required)
+  parseTopLevelDeclarationImpl(}, Instance of 'DirectiveContext')
+    parseMetadataStar(})
+      listener: beginMetadataStar(required)
+      listener: endMetadataStar(0)
+    parseTopLevelMemberImpl(})
+      listener: beginTopLevelMember(required)
+      parseTopLevelMethod(}, null, }, Instance of 'NoType', null, required)
+        listener: beginTopLevelMethod(}, null)
+        listener: handleNoType(})
+        ensureIdentifier(}, topLevelFunctionDeclaration)
+          listener: handleIdentifier(required, topLevelFunctionDeclaration)
+        parseMethodTypeVar(required)
+          listener: handleNoTypeVariables(()
+        parseGetterOrFormalParameters(required, required, false, MemberKind.TopLevelMethod)
+          parseFormalParameters(required, MemberKind.TopLevelMethod)
+            parseFormalParametersRest((, MemberKind.TopLevelMethod)
+              listener: beginFormalParameters((, MemberKind.TopLevelMethod)
+              parseOptionalNamedParameters((, MemberKind.TopLevelMethod)
+                listener: beginOptionalFormalParameters({)
+                parseFormalParameter({, FormalParameterKind.optionalNamed, MemberKind.TopLevelMethod)
+                  parseMetadataStar({)
+                    listener: beginMetadataStar(required)
+                    listener: endMetadataStar(0)
+                  listener: beginFormalParameter(required, MemberKind.TopLevelMethod, required, null, null)
+                  listener: handleIdentifier(int, typeReference)
+                  listener: handleNoTypeArguments(named)
+                  listener: handleType(int, null)
+                  ensureIdentifier(int, formalParameterDeclaration)
+                    listener: handleIdentifier(named, formalParameterDeclaration)
+                  listener: handleFormalParameterWithoutValue(})
+                  listener: endFormalParameter(null, null, named, null, null, FormalParameterKind.optionalNamed, MemberKind.TopLevelMethod)
+                listener: endOptionalFormalParameters(1, {, })
+              ensureCloseParen(}, ()
+              listener: endFormalParameters(1, (, ), MemberKind.TopLevelMethod)
+        parseAsyncModifierOpt())
+          listener: handleAsyncModifier(null, null)
+          inPlainSync()
+        parseFunctionBody(), false, false)
+          listener: beginBlockFunctionBody({)
+          notEofOrValue(}, print)
+          parseStatement({)
+            parseStatementX({)
+              parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+                looksLikeLocalFunction(print)
+                parseExpressionStatement({)
+                  parseExpression({)
+                    parsePrecedenceExpression({, 1, true)
+                      parseUnaryExpression({, true)
+                        parsePrimary({, expression)
+                          parseSendOrFunctionLiteral({, expression)
+                            looksLikeFunctionBody(;)
+                            parseSend({, expression)
+                              ensureIdentifier({, expression)
+                                listener: handleIdentifier(print, expression)
+                              listener: handleNoTypeArguments(()
+                              parseArgumentsOpt(print)
+                                parseArguments(print)
+                                  parseArgumentsRest(()
+                                    listener: beginArguments(()
+                                    parseExpression(()
+                                      parsePrecedenceExpression((, 1, true)
+                                        parseUnaryExpression((, true)
+                                          parsePrimary((, expression)
+                                            parseLiteralString(()
+                                              parseSingleLiteralString(()
+                                                listener: beginLiteralString("hello")
+                                                listener: endLiteralString(0, ))
+                                    listener: endArguments(1, (, ))
+                              listener: handleSend(print, ;)
+                  ensureSemicolon())
+                  listener: handleExpressionStatement(;)
+          notEofOrValue(}, })
+          listener: endBlockFunctionBody(1, {, })
+        listener: endTopLevelMethod(required, null, })
+  listener: endTopLevelDeclaration(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(X, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, X)
+        parseClass(X, class, class, X)
+          parseClassHeaderOpt(X, class, class)
+            parseClassExtendsOpt(X)
+              listener: handleNoType(X)
+              listener: handleClassExtends(null)
+            parseWithClauseOpt(X)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(X)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(X, DeclarationKind.Class, X)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, required)
+            parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, X)
+              parseMetadataStar({)
+                listener: beginMetadataStar(required)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              parseMethod({, null, null, null, null, null, {, Instance of 'NoType', null, required, DeclarationKind.Class, X)
+                listener: beginMethod(null, null, null, null, null, required)
+                listener: handleNoType({)
+                ensureIdentifier({, methodDeclaration)
+                  listener: handleIdentifier(required, methodDeclaration)
+                parseQualifiedRestOpt(required, methodDeclarationContinuation)
+                parseMethodTypeVar(required)
+                  listener: handleNoTypeVariables(()
+                parseGetterOrFormalParameters(required, required, false, MemberKind.NonStaticMethod)
+                  parseFormalParameters(required, MemberKind.NonStaticMethod)
+                    parseFormalParametersRest((, MemberKind.NonStaticMethod)
+                      listener: beginFormalParameters((, MemberKind.NonStaticMethod)
+                      listener: endFormalParameters(0, (, ), MemberKind.NonStaticMethod)
+                parseInitializersOpt())
+                  listener: handleNoInitializers()
+                parseAsyncModifierOpt())
+                  listener: handleAsyncModifier(null, null)
+                  inPlainSync()
+                inPlainSync()
+                parseFunctionBody(), false, true)
+                  listener: beginBlockFunctionBody({)
+                  notEofOrValue(}, print)
+                  parseStatement({)
+                    parseStatementX({)
+                      parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false)
+                        looksLikeLocalFunction(print)
+                        parseExpressionStatement({)
+                          parseExpression({)
+                            parsePrecedenceExpression({, 1, true)
+                              parseUnaryExpression({, true)
+                                parsePrimary({, expression)
+                                  parseSendOrFunctionLiteral({, expression)
+                                    looksLikeFunctionBody(;)
+                                    parseSend({, expression)
+                                      ensureIdentifier({, expression)
+                                        listener: handleIdentifier(print, expression)
+                                      listener: handleNoTypeArguments(()
+                                      parseArgumentsOpt(print)
+                                        parseArguments(print)
+                                          parseArgumentsRest(()
+                                            listener: beginArguments(()
+                                            parseExpression(()
+                                              parsePrecedenceExpression((, 1, true)
+                                                parseUnaryExpression((, true)
+                                                  parsePrimary((, expression)
+                                                    parseLiteralString(()
+                                                      parseSingleLiteralString(()
+                                                        listener: beginLiteralString("hello")
+                                                        listener: endLiteralString(0, ))
+                                            listener: endArguments(1, (, ))
+                                      listener: handleSend(print, ;)
+                          ensureSemicolon())
+                          listener: handleExpressionStatement(;)
+                  notEofOrValue(}, })
+                  listener: endBlockFunctionBody(1, {, })
+                listener: endClassMethod(null, required, (, null, })
+              listener: endMember()
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration(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(Y, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, Y)
+        parseClass(Y, class, class, Y)
+          parseClassHeaderOpt(Y, class, class)
+            parseClassExtendsOpt(Y)
+              listener: handleNoType(Y)
+              listener: handleClassExtends(null)
+            parseWithClauseOpt(Y)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(Y)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(Y, DeclarationKind.Class, Y)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, int)
+            parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Class, Y)
+              parseMetadataStar({)
+                listener: beginMetadataStar(int)
+                listener: endMetadataStar(0)
+              listener: beginMember()
+              parseFields({, null, null, null, null, null, {, Instance of 'SimpleType', required, DeclarationKind.Class)
+                listener: handleIdentifier(int, typeReference)
+                listener: handleNoTypeArguments(required)
+                listener: handleType(int, null)
+                ensureIdentifier(int, fieldDeclaration)
+                  listener: handleIdentifier(required, fieldDeclaration)
+                parseFieldInitializerOpt(required, required, null, null, DeclarationKind.Class)
+                  listener: beginFieldInitializer(=)
+                  parseExpression(=)
+                    parsePrecedenceExpression(=, 1, true)
+                      parseUnaryExpression(=, true)
+                        parsePrimary(=, expression)
+                          parseLiteralInt(=)
+                            listener: handleLiteralInt(42)
+                  listener: endFieldInitializer(=, ;)
+                listener: endClassFields(null, null, null, null, 1, int, ;)
+              listener: endMember()
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 1, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(main)
+  listener: endCompilationUnit(4, )
diff --git a/pkg/front_end/pubspec.yaml b/pkg/front_end/pubspec.yaml
index 496a779..1272291 100644
--- a/pkg/front_end/pubspec.yaml
+++ b/pkg/front_end/pubspec.yaml
@@ -1,7 +1,7 @@
 name: front_end
 # Currently, front_end API is not stable and users should not
 # depend on semver semantics when depending on this package.
-version: 0.1.27
+version: 0.1.28
 author: Dart Team <misc@dartlang.org>
 description: Front end for compilation of Dart code.
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/front_end
diff --git a/pkg/front_end/test/analyser_ignored/load_dill_twice_lib_1.dart b/pkg/front_end/test/analyser_ignored/load_dill_twice_lib_1.dart
new file mode 100644
index 0000000..ca76918
--- /dev/null
+++ b/pkg/front_end/test/analyser_ignored/load_dill_twice_lib_1.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.
+
+export 'load_dill_twice_lib_2.dart';
+
+// Use annotation to force proper printing.
+
+typedef myTypedefWithNamed(@Foo int a, {@Foo int b});
+typedef myTypedefWithOptionalPositional(@Foo int a, [@Foo int b]);
+
+const Foo = 42;
+
+class Bar {}
+
+extension BarX on Bar {
+  void hello() {
+    print("Hello!");
+  }
+}
diff --git a/pkg/front_end/test/analyser_ignored/load_dill_twice_lib_2.dart b/pkg/front_end/test/analyser_ignored/load_dill_twice_lib_2.dart
new file mode 100644
index 0000000..5e9d38a
--- /dev/null
+++ b/pkg/front_end/test/analyser_ignored/load_dill_twice_lib_2.dart
@@ -0,0 +1,5 @@
+// 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 foo() => 42;
diff --git a/pkg/front_end/test/analyser_ignored/load_dill_twice_test.dart b/pkg/front_end/test/analyser_ignored/load_dill_twice_test.dart
new file mode 100644
index 0000000..f587774
--- /dev/null
+++ b/pkg/front_end/test/analyser_ignored/load_dill_twice_test.dart
@@ -0,0 +1,79 @@
+// 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 'dart:io' show Platform, exit;
+
+import 'package:kernel/binary/ast_from_binary.dart' show BinaryBuilder;
+
+import 'package:kernel/text/ast_to_text.dart' show componentToString;
+
+import 'package:kernel/kernel.dart' show Component;
+
+import '../incremental_load_from_dill_test.dart' show normalCompileToBytes;
+
+main() async {
+  List<int> bytes = await normalCompileToBytes(
+      Platform.script.resolve("load_dill_twice_lib_1.dart"));
+
+  Component c = new Component();
+  new BinaryBuilder(bytes).readComponent(c);
+  String loadedOnceString = componentToString(c);
+  new BinaryBuilder(bytes).readComponent(c);
+  String loadedTwiceString = componentToString(c);
+
+  if (loadedOnceString != loadedTwiceString) {
+    print("Loading the dill twice produces a different textual representation");
+    List<String> linesOnce = loadedOnceString.split("\n");
+    List<String> linesTwice = loadedTwiceString.split("\n");
+
+    if (linesOnce.length != linesTwice.length) {
+      print("Number of lines differ! "
+          "(${linesOnce.length} vs ${linesTwice.length})");
+    }
+
+    // Do some simple and stupid diff.
+    int i = 0;
+    int j = 0;
+    while (i < linesOnce.length || j < linesTwice.length) {
+      if (i < linesOnce.length && j < linesTwice.length) {
+        if (linesOnce[i] == linesTwice[j]) {
+          i++;
+          j++;
+        } else {
+          // Search for line from linesOnce in linesTwice
+          bool good = false;
+          for (int k = j + 1; k < linesTwice.length && k < j + 100; k++) {
+            if (linesOnce[i] == linesTwice[k]) {
+              // Inserted lines between j and k.
+              for (int k2 = j; k2 < k; k2++) {
+                print("+ ${linesTwice[k2]}");
+              }
+              i++;
+              j = k + 1;
+              good = true;
+              break;
+            }
+          }
+          if (!good) {
+            // Assume lines deleted.
+            print("- ${linesOnce[i]}");
+            i++;
+          }
+        }
+      } else if (i < linesOnce.length) {
+        // Rest from linesOnce was deleted.
+        for (; i < linesOnce.length; i++) {
+          print("- ${linesOnce[i]}");
+        }
+      } else if (j < linesTwice.length) {
+        // Rest from linesTwice was added.
+        for (; j < linesTwice.length; j++) {
+          print("+ ${linesTwice[j]}");
+        }
+      }
+    }
+
+    exit(1);
+  }
+}
diff --git a/pkg/front_end/test/binary_md_dill_reader.dart b/pkg/front_end/test/binary_md_dill_reader.dart
index 44e75c8..ab2c574 100644
--- a/pkg/front_end/test/binary_md_dill_reader.dart
+++ b/pkg/front_end/test/binary_md_dill_reader.dart
@@ -755,29 +755,45 @@
     return result;
   }
 
+  List<String> stack = [];
+
+  int outputLines = 0;
+
+  void printDifference(String s) {
+    outputTo.writeln("----------");
+    outputTo.writeln(s);
+    outputTo.writeln("'Stacktrace':");
+    stack.forEach(outputTo.writeln);
+    outputLines += 3 + stack.length;
+  }
+
   bool _compareInternal(dynamic a, dynamic b) {
     if (a.runtimeType != b.runtimeType) {
-      outputTo.writeln(
+      printDifference(
           "Different runtime types (${a.runtimeType} and ${b.runtimeType})");
       return false;
     }
+
+    bool result = true;
     if (a is List) {
       List listA = a;
       List listB = b;
+      int length = listA.length;
       if (listA.length != listB.length) {
-        outputTo.writeln(
-            "Lists have different length (${listA.length} vs ${listB.length} "
-            "${_getTag(a)}");
-        return false;
+        printDifference(
+            "Lists have different length (${listA.length} vs ${listB.length})");
+        result = false;
+        if (listB.length < listA.length) length = listB.length;
       }
-      for (int i = 0; i < listA.length; i++) {
+      for (int i = 0; i < length; i++) {
+        stack.add("Lists at index $i ${_getTag(a)}");
         if (!_compareInternal(listA[i], listB[i])) {
-          outputTo
-              .writeln("Lists have different values at index $i ${_getTag(a)}");
-          return false;
+          result = false;
         }
+        stack.removeLast();
+        if (outputLines > 1000) return result;
       }
-      return true;
+      return result;
     }
 
     if (a is Map<String, dynamic>) {
@@ -786,23 +802,24 @@
       for (String key in mapA.keys) {
         dynamic valueA = mapA[key];
         dynamic valueB = mapB[key];
+        stack.add("Map with key '$key' ${_getTag(a)}");
         if (!_compareInternal(valueA, valueB)) {
-          outputTo.writeln(
-              "Map with key '$key' has different values ${_getTag(a)}");
-          return false;
+          result = false;
         }
+        stack.removeLast();
+        if (outputLines > 1000) return result;
       }
       if (mapA.length != mapB.length) {
-        outputTo.writeln("Maps have different number of entries "
+        printDifference("Maps have different number of entries "
             "(${mapA.length} vs ${mapB.length}). ${_getTag(a)}");
-        return false;
+        result = false;
       }
-      return true;
+      return result;
     }
 
     if (a is int) {
       if (a != b) {
-        outputTo.writeln("Integers differ: $a vs $b");
+        printDifference("Integers differ: $a vs $b");
         return false;
       }
       return true;
diff --git a/pkg/front_end/test/explicit_creation_test.dart b/pkg/front_end/test/explicit_creation_test.dart
index d655ac1..cbedba9 100644
--- a/pkg/front_end/test/explicit_creation_test.dart
+++ b/pkg/front_end/test/explicit_creation_test.dart
@@ -9,8 +9,12 @@
 import 'package:front_end/src/base/processed_options.dart';
 import 'package:front_end/src/compute_platform_binaries_location.dart'
     show computePlatformBinariesLocation;
-import 'package:front_end/src/fasta/builder/builder.dart';
 import 'package:front_end/src/fasta/builder/declaration_builder.dart';
+import 'package:front_end/src/fasta/builder/field_builder.dart';
+import 'package:front_end/src/fasta/builder/library_builder.dart';
+import 'package:front_end/src/fasta/builder/modifier_builder.dart';
+import 'package:front_end/src/fasta/builder/type_declaration_builder.dart';
+import 'package:front_end/src/fasta/builder/unresolved_type.dart';
 import 'package:front_end/src/fasta/compiler_context.dart';
 import 'package:front_end/src/fasta/constant_context.dart';
 import 'package:front_end/src/fasta/dill/dill_target.dart';
@@ -19,6 +23,7 @@
 import 'package:front_end/src/fasta/kernel/constness.dart';
 import 'package:front_end/src/fasta/kernel/kernel_target.dart';
 import 'package:front_end/src/fasta/severity.dart';
+import 'package:front_end/src/fasta/scope.dart';
 import 'package:front_end/src/fasta/source/diet_listener.dart';
 import 'package:front_end/src/fasta/source/source_library_builder.dart';
 import 'package:front_end/src/fasta/source/source_loader.dart';
diff --git a/pkg/front_end/test/extensions/extensions_test.dart b/pkg/front_end/test/extensions/extensions_test.dart
index 880d249..d64295f 100644
--- a/pkg/front_end/test/extensions/extensions_test.dart
+++ b/pkg/front_end/test/extensions/extensions_test.dart
@@ -5,9 +5,16 @@
 import 'dart:io' show Directory, Platform;
 import 'package:front_end/src/api_prototype/experimental_flags.dart'
     show ExperimentalFlag;
-import 'package:front_end/src/fasta/builder/builder.dart';
+
+import 'package:front_end/src/fasta/builder/class_builder.dart';
 import 'package:front_end/src/fasta/builder/extension_builder.dart';
-import 'package:front_end/src/fasta/kernel/kernel_builder.dart';
+import 'package:front_end/src/fasta/builder/formal_parameter_builder.dart';
+import 'package:front_end/src/fasta/builder/function_builder.dart';
+import 'package:front_end/src/fasta/builder/library_builder.dart';
+import 'package:front_end/src/fasta/builder/member_builder.dart';
+import 'package:front_end/src/fasta/builder/type_builder.dart';
+import 'package:front_end/src/fasta/builder/type_variable_builder.dart';
+
 import 'package:front_end/src/testing/id.dart' show ActualData, Id;
 import 'package:front_end/src/testing/features.dart';
 import 'package:front_end/src/testing/id_testing.dart'
diff --git a/pkg/front_end/test/fasta/ambiguous_export_test.dart b/pkg/front_end/test/fasta/ambiguous_export_test.dart
index abe0fcc..b7f09ee 100644
--- a/pkg/front_end/test/fasta/ambiguous_export_test.dart
+++ b/pkg/front_end/test/fasta/ambiguous_export_test.dart
@@ -6,8 +6,7 @@
 
 import 'package:expect/expect.dart' show Expect;
 
-import 'package:front_end/src/fasta/builder/builder.dart'
-    show InvalidTypeBuilder;
+import 'package:front_end/src/fasta/builder/invalid_type_declaration_builder.dart';
 
 import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;
 
@@ -34,7 +33,7 @@
       await target.loader.buildOutline(builder);
       builder.markAsReadyToFinalizeExports();
       var mainExport = builder.exportScope.local["main"];
-      Expect.isTrue(mainExport is InvalidTypeBuilder);
+      Expect.isTrue(mainExport is InvalidTypeDeclarationBuilder);
     });
   });
 }
diff --git a/pkg/front_end/test/fasta/flow_analysis/assigned_variables_test.dart b/pkg/front_end/test/fasta/flow_analysis/assigned_variables_test.dart
index 5a79729..f3f9b1d 100644
--- a/pkg/front_end/test/fasta/flow_analysis/assigned_variables_test.dart
+++ b/pkg/front_end/test/fasta/flow_analysis/assigned_variables_test.dart
@@ -6,47 +6,104 @@
 import 'package:test/test.dart';
 
 main() {
+  test('capturedAnywhere records assignments in closures', () {
+    var assignedVariables = AssignedVariables<_Node, _Variable>();
+    var v1 = _Variable('v1');
+    var v2 = _Variable('v2');
+    var v3 = _Variable('v3');
+    assignedVariables.declare(v1);
+    assignedVariables.declare(v2);
+    assignedVariables.declare(v3);
+    assignedVariables.write(v1);
+    assignedVariables.beginNode();
+    assignedVariables.write(v2);
+    assignedVariables.endNode(_Node(), isClosure: true);
+    assignedVariables.write(v3);
+    assignedVariables.finish();
+    expect(assignedVariables.capturedAnywhere, {v2});
+  });
+
+  test('capturedAnywhere does not record variables local to a closure', () {
+    var assignedVariables = AssignedVariables<_Node, _Variable>();
+    var v1 = _Variable('v1');
+    var v2 = _Variable('v2');
+    assignedVariables.declare(v1);
+    assignedVariables.beginNode();
+    assignedVariables.declare(v2);
+    assignedVariables.write(v1);
+    assignedVariables.write(v2);
+    assignedVariables.endNode(_Node(), isClosure: true);
+    assignedVariables.finish();
+    expect(assignedVariables.capturedAnywhere, {v1});
+  });
+
+  test('writtenAnywhere records all assignments', () {
+    var assignedVariables = AssignedVariables<_Node, _Variable>();
+    var v1 = _Variable('v1');
+    var v2 = _Variable('v2');
+    var v3 = _Variable('v3');
+    assignedVariables.declare(v1);
+    assignedVariables.declare(v2);
+    assignedVariables.declare(v3);
+    assignedVariables.write(v1);
+    assignedVariables.beginNode();
+    assignedVariables.write(v2);
+    assignedVariables.endNode(_Node(), isClosure: true);
+    assignedVariables.write(v3);
+    assignedVariables.finish();
+    expect(assignedVariables.writtenAnywhere, {v1, v2, v3});
+  });
+
   test('writtenInNode ignores assignments outside the node', () {
     var assignedVariables = AssignedVariables<_Node, _Variable>();
     var v1 = _Variable('v1');
     var v2 = _Variable('v2');
+    assignedVariables.declare(v1);
+    assignedVariables.declare(v2);
     assignedVariables.write(v1);
     assignedVariables.beginNode();
     var node = _Node();
     assignedVariables.endNode(node);
     assignedVariables.write(v2);
+    assignedVariables.finish();
     expect(assignedVariables.writtenInNode(node), isEmpty);
   });
 
   test('writtenInNode records assignments inside the node', () {
     var assignedVariables = AssignedVariables<_Node, _Variable>();
     var v1 = _Variable('v1');
+    assignedVariables.declare(v1);
     assignedVariables.beginNode();
     assignedVariables.write(v1);
     var node = _Node();
     assignedVariables.endNode(node);
+    assignedVariables.finish();
     expect(assignedVariables.writtenInNode(node), {v1});
   });
 
   test('writtenInNode records assignments in a nested node', () {
     var assignedVariables = AssignedVariables<_Node, _Variable>();
     var v1 = _Variable('v1');
+    assignedVariables.declare(v1);
     assignedVariables.beginNode();
     assignedVariables.beginNode();
     assignedVariables.write(v1);
     assignedVariables.endNode(_Node());
     var node = _Node();
     assignedVariables.endNode(node);
+    assignedVariables.finish();
     expect(assignedVariables.writtenInNode(node), {v1});
   });
 
   test('writtenInNode records assignments in a closure', () {
     var assignedVariables = AssignedVariables<_Node, _Variable>();
     var v1 = _Variable('v1');
-    assignedVariables.beginNode(isClosure: true);
+    assignedVariables.declare(v1);
+    assignedVariables.beginNode();
     assignedVariables.write(v1);
     var node = _Node();
     assignedVariables.endNode(node, isClosure: true);
+    assignedVariables.finish();
     expect(assignedVariables.writtenInNode(node), {v1});
   });
 
@@ -54,29 +111,83 @@
     var assignedVariables = AssignedVariables<_Node, _Variable>();
     var v1 = _Variable('v1');
     var v2 = _Variable('v2');
-    assignedVariables.beginNode(isClosure: true);
+    assignedVariables.declare(v1);
+    assignedVariables.declare(v2);
+    assignedVariables.beginNode();
     assignedVariables.write(v1);
     assignedVariables.endNode(_Node(), isClosure: true);
     assignedVariables.beginNode();
     var node = _Node();
     assignedVariables.endNode(node);
-    assignedVariables.beginNode(isClosure: true);
+    assignedVariables.beginNode();
     assignedVariables.write(v2);
     assignedVariables.endNode(_Node(), isClosure: true);
+    assignedVariables.finish();
     expect(assignedVariables.capturedInNode(node), isEmpty);
   });
 
   test('capturedInNode records assignments in nested closures', () {
     var assignedVariables = AssignedVariables<_Node, _Variable>();
     var v1 = _Variable('v1');
+    assignedVariables.declare(v1);
     assignedVariables.beginNode();
-    assignedVariables.beginNode(isClosure: true);
+    assignedVariables.beginNode();
     assignedVariables.write(v1);
     assignedVariables.endNode(_Node(), isClosure: true);
     var node = _Node();
     assignedVariables.endNode(node);
+    assignedVariables.finish();
     expect(assignedVariables.capturedInNode(node), {v1});
   });
+
+  group('Variables do not percolate beyond the scope they were declared in',
+      () {
+    test('Non-closure scope', () {
+      var assignedVariables = AssignedVariables<_Node, _Variable>();
+      var v1 = _Variable('v1');
+      var v2 = _Variable('v2');
+      assignedVariables.beginNode();
+      assignedVariables.beginNode();
+      assignedVariables.declare(v1);
+      assignedVariables.declare(v2);
+      assignedVariables.write(v1);
+      assignedVariables.beginNode();
+      assignedVariables.write(v2);
+      assignedVariables.endNode(_Node(), isClosure: true);
+      var innerNode = _Node();
+      assignedVariables.endNode(innerNode, isClosure: false);
+      var outerNode = _Node();
+      assignedVariables.endNode(outerNode);
+      assignedVariables.finish();
+      expect(assignedVariables.writtenInNode(innerNode), isEmpty);
+      expect(assignedVariables.capturedInNode(innerNode), isEmpty);
+      expect(assignedVariables.writtenInNode(outerNode), isEmpty);
+      expect(assignedVariables.capturedInNode(outerNode), isEmpty);
+    });
+
+    test('Closure scope', () {
+      var assignedVariables = AssignedVariables<_Node, _Variable>();
+      var v1 = _Variable('v1');
+      var v2 = _Variable('v2');
+      assignedVariables.beginNode();
+      assignedVariables.beginNode();
+      assignedVariables.declare(v1);
+      assignedVariables.declare(v2);
+      assignedVariables.write(v1);
+      assignedVariables.beginNode();
+      assignedVariables.write(v2);
+      assignedVariables.endNode(_Node(), isClosure: true);
+      var innerNode = _Node();
+      assignedVariables.endNode(innerNode, isClosure: true);
+      var outerNode = _Node();
+      assignedVariables.endNode(outerNode);
+      assignedVariables.finish();
+      expect(assignedVariables.writtenInNode(innerNode), isEmpty);
+      expect(assignedVariables.capturedInNode(innerNode), isEmpty);
+      expect(assignedVariables.writtenInNode(outerNode), isEmpty);
+      expect(assignedVariables.capturedInNode(outerNode), isEmpty);
+    });
+  });
 }
 
 class _Node {}
diff --git a/pkg/front_end/test/fasta/flow_analysis/flow_analysis_test.dart b/pkg/front_end/test/fasta/flow_analysis/flow_analysis_test.dart
index a171dbf..3e3b6cc 100644
--- a/pkg/front_end/test/fasta/flow_analysis/flow_analysis_test.dart
+++ b/pkg/front_end/test/fasta/flow_analysis/flow_analysis_test.dart
@@ -105,13 +105,18 @@
       });
     });
 
-    test('conditionEqNull(notEqual: true) promotes true branch', () {
+    test('equalityOp(x != null) promotes true branch', () {
       var h = _Harness();
       var x = h.addVar('x', 'int?');
       h.run((flow) {
         h.declare(x, initialized: true);
+        var varExpr = _Expression();
+        flow.variableRead(varExpr, x);
+        flow.equalityOp_rightBegin(varExpr);
+        var nullExpr = _Expression();
+        flow.nullLiteral(nullExpr);
         var expr = _Expression();
-        flow.conditionEqNull(expr, x, notEqual: true);
+        flow.equalityOp_end(expr, nullExpr, notEqual: true);
         flow.ifStatement_thenBegin(expr);
         expect(flow.promotedType(x).type, 'int');
         flow.ifStatement_elseBegin();
@@ -120,13 +125,18 @@
       });
     });
 
-    test('conditionEqNull(notEqual: false) promotes false branch', () {
+    test('equalityOp(x == null) promotes false branch', () {
       var h = _Harness();
       var x = h.addVar('x', 'int?');
       h.run((flow) {
         h.declare(x, initialized: true);
+        var varExpr = _Expression();
+        flow.variableRead(varExpr, x);
+        flow.equalityOp_rightBegin(varExpr);
+        var nullExpr = _Expression();
+        flow.nullLiteral(nullExpr);
         var expr = _Expression();
-        flow.conditionEqNull(expr, x, notEqual: false);
+        flow.equalityOp_end(expr, nullExpr, notEqual: false);
         flow.ifStatement_thenBegin(expr);
         expect(flow.promotedType(x), isNull);
         flow.ifStatement_elseBegin();
@@ -135,6 +145,63 @@
       });
     });
 
+    test('equalityOp(null != x) promotes true branch', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        var nullExpr = _Expression();
+        flow.nullLiteral(nullExpr);
+        flow.equalityOp_rightBegin(nullExpr);
+        var varExpr = _Expression();
+        flow.variableRead(varExpr, x);
+        var expr = _Expression();
+        flow.equalityOp_end(expr, varExpr, notEqual: true);
+        flow.ifStatement_thenBegin(expr);
+        expect(flow.promotedType(x).type, 'int');
+        flow.ifStatement_elseBegin();
+        expect(flow.promotedType(x), isNull);
+        flow.ifStatement_end(true);
+      });
+    });
+
+    test('equalityOp(null == x) promotes false branch', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        var nullExpr = _Expression();
+        flow.nullLiteral(nullExpr);
+        flow.equalityOp_rightBegin(nullExpr);
+        var varExpr = _Expression();
+        flow.variableRead(varExpr, x);
+        var expr = _Expression();
+        flow.equalityOp_end(expr, varExpr, notEqual: false);
+        flow.ifStatement_thenBegin(expr);
+        expect(flow.promotedType(x), isNull);
+        flow.ifStatement_elseBegin();
+        expect(flow.promotedType(x).type, 'int');
+        flow.ifStatement_end(true);
+      });
+    });
+
+    test('conditionEqNull() does not promote write-captured vars', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?', hasWrites: true, isCaptured: true);
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.if_(h.notNull(x), () {
+          expect(flow.promotedType(x).type, 'int');
+        });
+        h.function({x}, () {
+          flow.write(x);
+        });
+        h.if_(h.notNull(x), () {
+          expect(flow.promotedType(x), isNull);
+        });
+      });
+    });
+
     test('doStatement_bodyBegin() un-promotes', () {
       var h = _Harness();
       var x = h.addVar('x', 'int?');
@@ -142,20 +209,38 @@
         h.declare(x, initialized: true);
         h.promote(x, 'int');
         expect(flow.promotedType(x).type, 'int');
-        flow.doStatement_bodyBegin(_Statement(), {x});
+        flow.doStatement_bodyBegin(_Statement(), {x}, {});
         expect(flow.promotedType(x), isNull);
         flow.doStatement_conditionBegin();
         flow.doStatement_end(_Expression());
       });
     });
 
+    test('doStatement_bodyBegin() handles write captures in the loop', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?', hasWrites: true, isCaptured: true);
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        flow.doStatement_bodyBegin(_Statement(), {x}, {x});
+        h.promote(x, 'int');
+        // The promotion should have no effect, because the second time through
+        // the loop, x has been write-captured.
+        expect(flow.promotedType(x), isNull);
+        h.function({x}, () {
+          flow.write(x);
+        });
+        flow.doStatement_conditionBegin();
+        flow.doStatement_end(_Expression());
+      });
+    });
+
     test('doStatement_conditionBegin() joins continue state', () {
       var h = _Harness();
       var x = h.addVar('x', 'int?');
       h.run((flow) {
         h.declare(x, initialized: true);
         var stmt = _Statement();
-        flow.doStatement_bodyBegin(stmt, {});
+        flow.doStatement_bodyBegin(stmt, {}, {});
         h.if_(h.notNull(x), () {
           flow.handleContinue(stmt);
         });
@@ -174,7 +259,7 @@
       var x = h.addVar('x', 'int?');
       h.run((flow) {
         h.declare(x, initialized: true);
-        flow.doStatement_bodyBegin(_Statement(), {});
+        flow.doStatement_bodyBegin(_Statement(), {}, {});
         flow.doStatement_conditionBegin();
         expect(flow.promotedType(x), isNull);
         flow.doStatement_end(h.eqNull(x)());
@@ -192,14 +277,34 @@
 
     test('for_conditionBegin() un-promotes', () {
       var h = _Harness();
-      var x = h.addVar('x', 'int?');
+      var x = h.addVar('x', 'int?', hasWrites: true);
       h.run((flow) {
         h.declare(x, initialized: true);
         h.promote(x, 'int');
         expect(flow.promotedType(x).type, 'int');
-        flow.for_conditionBegin({x});
+        flow.for_conditionBegin({x}, {});
         expect(flow.promotedType(x), isNull);
         flow.for_bodyBegin(_Statement(), _Expression());
+        flow.write(x);
+        flow.for_updaterBegin();
+        flow.for_end();
+      });
+    });
+
+    test('for_conditionBegin() handles write captures in the loop', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?', hasWrites: true, isCaptured: true);
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.promote(x, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        flow.for_conditionBegin({x}, {x});
+        h.promote(x, 'int');
+        expect(flow.promotedType(x), isNull);
+        h.function({x}, () {
+          flow.write(x);
+        });
+        flow.for_bodyBegin(_Statement(), _Expression());
         flow.for_updaterBegin();
         flow.for_end();
       });
@@ -212,8 +317,8 @@
       h.run((flow) {
         h.declare(y, initialized: true);
         h.promote(y, 'int');
-        flow.for_conditionBegin({x});
-        flow.write(x);
+        flow.for_conditionBegin({x}, {});
+        flow.initialize(x);
         flow.for_bodyBegin(_Statement(), _Expression());
         flow.for_updaterBegin();
         flow.for_end();
@@ -223,7 +328,7 @@
     test('for_bodyBegin() handles empty condition', () {
       var h = _Harness();
       h.run((flow) {
-        flow.for_conditionBegin({});
+        flow.for_conditionBegin({}, {});
         flow.for_bodyBegin(_Statement(), null);
         flow.for_updaterBegin();
         expect(flow.isReachable, isTrue);
@@ -237,7 +342,7 @@
       var x = h.addVar('x', 'int?');
       h.run((flow) {
         h.declare(x, initialized: true);
-        flow.for_conditionBegin({});
+        flow.for_conditionBegin({}, {});
         flow.for_bodyBegin(_Statement(), h.notNull(x)());
         expect(flow.promotedType(x).type, 'int');
         flow.for_updaterBegin();
@@ -251,7 +356,7 @@
       var x = h.addVar('x', 'int?');
       h.run((flow) {
         h.declare(x, initialized: true);
-        flow.for_conditionBegin({});
+        flow.for_conditionBegin({}, {});
         flow.for_bodyBegin(null, h.notNull(x)());
         flow.for_updaterBegin();
         flow.for_end();
@@ -271,7 +376,7 @@
         h.declare(y, initialized: true);
         h.declare(z, initialized: true);
         var stmt = _Statement();
-        flow.for_conditionBegin({});
+        flow.for_conditionBegin({}, {});
         flow.for_bodyBegin(stmt, h.expr());
         h.if_(h.expr, () {
           h.promote(x, 'int');
@@ -301,7 +406,7 @@
         h.declare(y, initialized: true);
         h.declare(z, initialized: true);
         var stmt = _Statement();
-        flow.for_conditionBegin({});
+        flow.for_conditionBegin({}, {});
         flow.for_bodyBegin(stmt, h.or(h.eqNull(x), h.eqNull(z))());
         h.if_(h.expr, () {
           h.promote(x, 'int');
@@ -318,13 +423,31 @@
 
     test('forEach_bodyBegin() un-promotes', () {
       var h = _Harness();
-      var x = h.addVar('x', 'int?');
+      var x = h.addVar('x', 'int?', hasWrites: true);
       h.run((flow) {
         h.declare(x, initialized: true);
         h.promote(x, 'int');
         expect(flow.promotedType(x).type, 'int');
-        flow.forEach_bodyBegin({x}, null);
+        flow.forEach_bodyBegin({x}, {}, null);
         expect(flow.promotedType(x), isNull);
+        flow.write(x);
+        flow.forEach_end();
+      });
+    });
+
+    test('forEach_bodyBegin() handles write captures in the loop', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?', hasWrites: true, isCaptured: true);
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.promote(x, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        flow.forEach_bodyBegin({x}, {x}, null);
+        h.promote(x, 'int');
+        expect(flow.promotedType(x), isNull);
+        h.function({x}, () {
+          flow.write(x);
+        });
         flow.forEach_end();
       });
     });
@@ -335,7 +458,7 @@
       h.run((flow) {
         h.declare(x, initialized: false);
         expect(flow.isAssigned(x), false);
-        flow.forEach_bodyBegin({x}, x);
+        flow.forEach_bodyBegin({x}, {}, x);
         expect(flow.isAssigned(x), true);
         flow.forEach_end();
         expect(flow.isAssigned(x), false);
@@ -347,7 +470,7 @@
       var x = h.addVar('x', 'int?');
       h.run((flow) {
         h.declare(x, initialized: true);
-        flow.forEach_bodyBegin({}, null);
+        flow.forEach_bodyBegin({}, {}, null);
         h.promote(x, 'int');
         expect(flow.promotedType(x).type, 'int');
         flow.forEach_end();
@@ -355,6 +478,138 @@
       });
     });
 
+    test('functionExpression_begin() cancels promotions of self-captured vars',
+        () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?', hasWrites: true, isCaptured: true);
+      var y = h.addVar('y', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.declare(y, initialized: true);
+        h.promote(x, 'int');
+        h.promote(y, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        expect(flow.promotedType(y).type, 'int');
+        flow.functionExpression_begin({x});
+        // x is unpromoted within the local function
+        expect(flow.promotedType(x), isNull);
+        expect(flow.promotedType(y).type, 'int');
+        flow.write(x);
+        h.promote(x, 'int');
+        flow.functionExpression_end();
+        // x is unpromoted after the local function too
+        expect(flow.promotedType(x), isNull);
+        expect(flow.promotedType(y).type, 'int');
+      });
+    });
+
+    test('functionExpression_begin() cancels promotions of other-captured vars',
+        () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?', hasWrites: true, isCaptured: true);
+      var y = h.addVar('y', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.declare(y, initialized: true);
+        h.promote(x, 'int');
+        h.promote(y, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        expect(flow.promotedType(y).type, 'int');
+        flow.functionExpression_begin({});
+        // x is unpromoted within the local function, because the write
+        // might have been captured by the time the local function executes.
+        expect(flow.promotedType(x), isNull);
+        expect(flow.promotedType(y).type, 'int');
+        // And any effort to promote x fails, because there is no way of knowing
+        // when the captured write might occur.
+        h.promote(x, 'int');
+        expect(flow.promotedType(x), isNull);
+        expect(flow.promotedType(y).type, 'int');
+        flow.functionExpression_end();
+        // x is still promoted after the local function, though, because the
+        // write hasn't been captured yet.
+        expect(flow.promotedType(x).type, 'int');
+        expect(flow.promotedType(y).type, 'int');
+        flow.functionExpression_begin({x});
+        // x is unpromoted inside this local function too.
+        expect(flow.promotedType(x), isNull);
+        expect(flow.promotedType(y).type, 'int');
+        flow.write(x);
+        flow.functionExpression_end();
+        // And since the second local function captured x, it remains
+        // unpromoted.
+        expect(flow.promotedType(x), isNull);
+        expect(flow.promotedType(y).type, 'int');
+      });
+    });
+
+    test('functionExpression_begin() cancels promotions of written vars', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?', hasWrites: true);
+      var y = h.addVar('y', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.declare(y, initialized: true);
+        h.promote(x, 'int');
+        h.promote(y, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        expect(flow.promotedType(y).type, 'int');
+        flow.functionExpression_begin({});
+        // x is unpromoted within the local function, because the write
+        // might have happened by the time the local function executes.
+        expect(flow.promotedType(x), isNull);
+        expect(flow.promotedType(y).type, 'int');
+        // But it can be re-promoted because the write isn't captured.
+        h.promote(x, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        expect(flow.promotedType(y).type, 'int');
+        flow.functionExpression_end();
+        // x is still promoted after the local function, though, because the
+        // write hasn't occurred yet.
+        expect(flow.promotedType(x).type, 'int');
+        expect(flow.promotedType(y).type, 'int');
+        flow.write(x);
+        // x is unpromoted now.
+        expect(flow.promotedType(x), isNull);
+        expect(flow.promotedType(y).type, 'int');
+      });
+    });
+
+    test('functionExpression_begin() handles not-yet-seen variables', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      var y = h.addVar('y', 'int?');
+      h.run((flow) {
+        h.declare(y, initialized: true);
+        h.promote(y, 'int');
+        flow.functionExpression_begin({x});
+        flow.functionExpression_end();
+        h.declare(x, initialized: true);
+        h.promote(x, 'int');
+        expect(flow.promotedType(x), isNull);
+      });
+    });
+
+    test('functionExpression_begin() handles not-yet-seen write-captured vars',
+        () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?', hasWrites: true, isCaptured: true);
+      var y = h.addVar('y', 'int?');
+      h.run((flow) {
+        h.declare(y, initialized: true);
+        h.promote(y, 'int');
+        flow.functionExpression_begin({});
+        h.promote(x, 'int');
+        // Promotion should not occur, because x might be write-captured by the
+        // time this code is reached.
+        expect(flow.promotedType(x), isNull);
+        flow.functionExpression_end();
+        flow.functionExpression_begin({x});
+        h.declare(x, initialized: true);
+        flow.functionExpression_end();
+      });
+    });
+
     test('ifStatement_end(false) keeps else branch if then branch exits', () {
       var h = _Harness();
       var x = h.addVar('x', 'int?');
@@ -399,6 +654,34 @@
       _checkIs('int', 'String', null);
     });
 
+    test('isExpression_end() does not promote write-captured vars', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?', hasWrites: true, isCaptured: true);
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.if_(h.isType(x, 'int'), () {
+          expect(flow.promotedType(x).type, 'int');
+        });
+        h.function({x}, () {
+          flow.write(x);
+        });
+        h.if_(h.isType(x, 'int'), () {
+          expect(flow.promotedType(x), isNull);
+        });
+      });
+    });
+
+    test('isExpression_end() handles not-yet-seen variables', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?', hasWrites: true, isCaptured: true);
+      h.run((flow) {
+        h.if_(h.isType(x, 'int'), () {
+          expect(flow.promotedType(x).type, 'int');
+        });
+        h.declare(x, initialized: true);
+      });
+    });
+
     test('logicalBinaryOp_rightBegin(isAnd: true) promotes in RHS', () {
       var h = _Harness();
       var x = h.addVar('x', 'int?');
@@ -485,6 +768,30 @@
       });
     });
 
+    test('nonNullAssert_end(x) promotes', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        var varExpr = _Expression();
+        flow.variableRead(varExpr, x);
+        flow.nonNullAssert_end(varExpr);
+        expect(flow.promotedType(x).type, 'int');
+      });
+    });
+
+    test('parenthesizedExpression preserves promotion behaviors', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?');
+      h.run((flow) {
+        h.if_(
+            h.parenthesized(h.notEqual(h.parenthesized(h.variableRead(x)),
+                h.parenthesized(h.nullLiteral))), () {
+          expect(flow.promotedType(x).type, 'int');
+        });
+      });
+    });
+
     test('promotedType handles not-yet-seen variables', () {
       // Note: this is needed for error recovery in the analyzer.
       var h = _Harness();
@@ -497,16 +804,16 @@
 
     test('switchStatement_beginCase(false) restores previous promotions', () {
       var h = _Harness();
-      var x = h.addVar('x', 'int?');
+      var x = h.addVar('x', 'int?', hasWrites: true);
       h.run((flow) {
         h.declare(x, initialized: true);
         h.promote(x, 'int');
         flow.switchStatement_expressionEnd(_Statement());
-        flow.switchStatement_beginCase(false, {x});
+        flow.switchStatement_beginCase(false, {x}, {});
         expect(flow.promotedType(x).type, 'int');
         flow.write(x);
         expect(flow.promotedType(x), isNull);
-        flow.switchStatement_beginCase(false, {x});
+        flow.switchStatement_beginCase(false, {x}, {});
         expect(flow.promotedType(x).type, 'int');
         flow.write(x);
         expect(flow.promotedType(x), isNull);
@@ -516,12 +823,12 @@
 
     test('switchStatement_beginCase(false) does not un-promote', () {
       var h = _Harness();
-      var x = h.addVar('x', 'int?');
+      var x = h.addVar('x', 'int?', hasWrites: true);
       h.run((flow) {
         h.declare(x, initialized: true);
         h.promote(x, 'int');
         flow.switchStatement_expressionEnd(_Statement());
-        flow.switchStatement_beginCase(false, {x});
+        flow.switchStatement_beginCase(false, {x}, {});
         expect(flow.promotedType(x).type, 'int');
         flow.write(x);
         expect(flow.promotedType(x), isNull);
@@ -529,14 +836,32 @@
       });
     });
 
-    test('switchStatement_beginCase(true) un-promotes', () {
+    test('switchStatement_beginCase(false) handles write captures in cases',
+        () {
       var h = _Harness();
-      var x = h.addVar('x', 'int?');
+      var x = h.addVar('x', 'int?', hasWrites: true, isCaptured: true);
       h.run((flow) {
         h.declare(x, initialized: true);
         h.promote(x, 'int');
         flow.switchStatement_expressionEnd(_Statement());
-        flow.switchStatement_beginCase(true, {x});
+        flow.switchStatement_beginCase(false, {x}, {x});
+        expect(flow.promotedType(x).type, 'int');
+        h.function({x}, () {
+          flow.write(x);
+        });
+        expect(flow.promotedType(x), isNull);
+        flow.switchStatement_end(false);
+      });
+    });
+
+    test('switchStatement_beginCase(true) un-promotes', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?', hasWrites: true);
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.promote(x, 'int');
+        flow.switchStatement_expressionEnd(_Statement());
+        flow.switchStatement_beginCase(true, {x}, {});
         expect(flow.promotedType(x), isNull);
         flow.write(x);
         expect(flow.promotedType(x), isNull);
@@ -544,10 +869,28 @@
       });
     });
 
+    test('switchStatement_beginCase(true) handles write captures in cases', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?', hasWrites: true, isCaptured: true);
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.promote(x, 'int');
+        flow.switchStatement_expressionEnd(_Statement());
+        flow.switchStatement_beginCase(true, {x}, {x});
+        h.promote(x, 'int');
+        expect(flow.promotedType(x), isNull);
+        h.function({x}, () {
+          flow.write(x);
+        });
+        expect(flow.promotedType(x), isNull);
+        flow.switchStatement_end(false);
+      });
+    });
+
     test('switchStatement_end(false) joins break and default', () {
       var h = _Harness();
       var x = h.addVar('x', 'int?');
-      var y = h.addVar('y', 'int?');
+      var y = h.addVar('y', 'int?', hasWrites: true);
       var z = h.addVar('z', 'int?');
       h.run((flow) {
         h.declare(x, initialized: true);
@@ -557,7 +900,7 @@
         h.promote(z, 'int');
         var stmt = _Statement();
         flow.switchStatement_expressionEnd(stmt);
-        flow.switchStatement_beginCase(false, {y});
+        flow.switchStatement_beginCase(false, {y}, {});
         h.promote(x, 'int');
         flow.write(y);
         flow.handleBreak(stmt);
@@ -571,8 +914,8 @@
     test('switchStatement_end(true) joins breaks', () {
       var h = _Harness();
       var w = h.addVar('w', 'int?');
-      var x = h.addVar('x', 'int?');
-      var y = h.addVar('y', 'int?');
+      var x = h.addVar('x', 'int?', hasWrites: true);
+      var y = h.addVar('y', 'int?', hasWrites: true);
       var z = h.addVar('z', 'int?');
       h.run((flow) {
         h.declare(w, initialized: true);
@@ -584,12 +927,12 @@
         h.promote(z, 'int');
         var stmt = _Statement();
         flow.switchStatement_expressionEnd(stmt);
-        flow.switchStatement_beginCase(false, {x, y});
+        flow.switchStatement_beginCase(false, {x, y}, {});
         h.promote(w, 'int');
         h.promote(y, 'int');
         flow.write(x);
         flow.handleBreak(stmt);
-        flow.switchStatement_beginCase(false, {x, y});
+        flow.switchStatement_beginCase(false, {x, y}, {});
         h.promote(w, 'int');
         h.promote(x, 'int');
         flow.write(y);
@@ -609,10 +952,10 @@
         h.declare(x, initialized: true);
         var stmt = _Statement();
         flow.switchStatement_expressionEnd(stmt);
-        flow.switchStatement_beginCase(false, {});
+        flow.switchStatement_beginCase(false, {}, {});
         h.promote(x, 'int');
         flow.handleBreak(stmt);
-        flow.switchStatement_beginCase(false, {});
+        flow.switchStatement_beginCase(false, {}, {});
         flow.switchStatement_end(true);
         expect(flow.promotedType(x), isNull);
       });
@@ -630,7 +973,7 @@
         h.promote(x, 'int');
         expect(flow.promotedType(x).type, 'int');
         expect(flow.promotedType(y).type, 'int');
-        flow.tryCatchStatement_bodyEnd({});
+        flow.tryCatchStatement_bodyEnd({}, {});
         flow.tryCatchStatement_catchBegin();
         expect(flow.promotedType(x), isNull);
         expect(flow.promotedType(y).type, 'int');
@@ -642,7 +985,7 @@
     test('tryCatchStatement_bodyEnd() un-promotes variables assigned in body',
         () {
       var h = _Harness();
-      var x = h.addVar('x', 'int?');
+      var x = h.addVar('x', 'int?', hasWrites: true);
       h.run((flow) {
         h.declare(x, initialized: true);
         h.promote(x, 'int');
@@ -651,7 +994,7 @@
         flow.write(x);
         h.promote(x, 'int');
         expect(flow.promotedType(x).type, 'int');
-        flow.tryCatchStatement_bodyEnd({x});
+        flow.tryCatchStatement_bodyEnd({x}, {});
         flow.tryCatchStatement_catchBegin();
         expect(flow.promotedType(x), isNull);
         flow.tryCatchStatement_catchEnd();
@@ -659,6 +1002,30 @@
       });
     });
 
+    test('tryCatchStatement_bodyEnd() preserves write captures in body', () {
+      // Note: it's not necessary for the write capture to survive to the end of
+      // the try body, because an exception could occur at any time.  We check
+      // this by putting an exit in the try body.
+      var h = _Harness();
+      var x = h.addVar('x', 'int?', hasWrites: true, isCaptured: true);
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.promote(x, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        flow.tryCatchStatement_bodyBegin();
+        h.function({x}, () {
+          flow.write(x);
+        });
+        flow.handleExit();
+        flow.tryCatchStatement_bodyEnd({x}, {x});
+        flow.tryCatchStatement_catchBegin();
+        h.promote(x, 'int');
+        expect(flow.promotedType(x), isNull);
+        flow.tryCatchStatement_catchEnd();
+        flow.tryCatchStatement_end();
+      });
+    });
+
     test('tryCatchStatement_catchBegin() restores previous post-body state',
         () {
       var h = _Harness();
@@ -666,7 +1033,7 @@
       h.run((flow) {
         h.declare(x, initialized: true);
         flow.tryCatchStatement_bodyBegin();
-        flow.tryCatchStatement_bodyEnd({});
+        flow.tryCatchStatement_bodyEnd({}, {});
         flow.tryCatchStatement_catchBegin();
         h.promote(x, 'int');
         expect(flow.promotedType(x).type, 'int');
@@ -691,7 +1058,7 @@
         flow.tryCatchStatement_bodyBegin();
         h.promote(x, 'int');
         h.promote(y, 'int');
-        flow.tryCatchStatement_bodyEnd({});
+        flow.tryCatchStatement_bodyEnd({}, {});
         flow.tryCatchStatement_catchBegin();
         h.promote(x, 'int');
         h.promote(z, 'int');
@@ -716,7 +1083,7 @@
         h.declare(z, initialized: true);
         flow.tryCatchStatement_bodyBegin();
         flow.handleExit();
-        flow.tryCatchStatement_bodyEnd({});
+        flow.tryCatchStatement_bodyEnd({}, {});
         flow.tryCatchStatement_catchBegin();
         h.promote(x, 'int');
         h.promote(y, 'int');
@@ -746,7 +1113,7 @@
         h.promote(x, 'int');
         expect(flow.promotedType(x).type, 'int');
         expect(flow.promotedType(y).type, 'int');
-        flow.tryFinallyStatement_finallyBegin({});
+        flow.tryFinallyStatement_finallyBegin({}, {});
         expect(flow.promotedType(x), isNull);
         expect(flow.promotedType(y).type, 'int');
         flow.tryFinallyStatement_end({});
@@ -757,7 +1124,7 @@
         'tryFinallyStatement_finallyBegin() un-promotes variables assigned in '
         'body', () {
       var h = _Harness();
-      var x = h.addVar('x', 'int?');
+      var x = h.addVar('x', 'int?', hasWrites: true);
       h.run((flow) {
         h.declare(x, initialized: true);
         h.promote(x, 'int');
@@ -766,7 +1133,28 @@
         flow.write(x);
         h.promote(x, 'int');
         expect(flow.promotedType(x).type, 'int');
-        flow.tryFinallyStatement_finallyBegin({x});
+        flow.tryFinallyStatement_finallyBegin({x}, {});
+        expect(flow.promotedType(x), isNull);
+        flow.tryFinallyStatement_end({});
+      });
+    });
+
+    test('tryFinallyStatement_finallyBegin() preserves write captures in body',
+        () {
+      // Note: it's not necessary for the write capture to survive to the end of
+      // the try body, because an exception could occur at any time.  We check
+      // this by putting an exit in the try body.
+      var h = _Harness();
+      var x = h.addVar('x', 'int?', hasWrites: true, isCaptured: true);
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        flow.tryFinallyStatement_bodyBegin();
+        h.function({x}, () {
+          flow.write(x);
+        });
+        flow.handleExit();
+        flow.tryFinallyStatement_finallyBegin({x}, {x});
+        h.promote(x, 'int');
         expect(flow.promotedType(x), isNull);
         flow.tryFinallyStatement_end({});
       });
@@ -782,7 +1170,7 @@
         flow.tryFinallyStatement_bodyBegin();
         h.promote(x, 'int');
         expect(flow.promotedType(x).type, 'int');
-        flow.tryFinallyStatement_finallyBegin({});
+        flow.tryFinallyStatement_finallyBegin({}, {});
         expect(flow.promotedType(x), isNull);
         h.promote(y, 'int');
         expect(flow.promotedType(y).type, 'int');
@@ -797,15 +1185,15 @@
         'tryFinallyStatement_end() does not restore try body promotions for '
         'variables assigned in finally', () {
       var h = _Harness();
-      var x = h.addVar('x', 'int?');
-      var y = h.addVar('y', 'int?');
+      var x = h.addVar('x', 'int?', hasWrites: true);
+      var y = h.addVar('y', 'int?', hasWrites: true);
       h.run((flow) {
         h.declare(x, initialized: true);
         h.declare(y, initialized: true);
         flow.tryFinallyStatement_bodyBegin();
         h.promote(x, 'int');
         expect(flow.promotedType(x).type, 'int');
-        flow.tryFinallyStatement_finallyBegin({});
+        flow.tryFinallyStatement_finallyBegin({}, {});
         expect(flow.promotedType(x), isNull);
         flow.write(x);
         flow.write(y);
@@ -827,13 +1215,32 @@
         h.declare(x, initialized: true);
         h.promote(x, 'int');
         expect(flow.promotedType(x).type, 'int');
-        flow.whileStatement_conditionBegin({x});
+        flow.whileStatement_conditionBegin({x}, {});
         expect(flow.promotedType(x), isNull);
         flow.whileStatement_bodyBegin(_Statement(), _Expression());
         flow.whileStatement_end();
       });
     });
 
+    test('whileStatement_conditionBegin() handles write captures in the loop',
+        () {
+      var h = _Harness();
+      var x = h.addVar('x', 'int?', hasWrites: true, isCaptured: true);
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.promote(x, 'int');
+        expect(flow.promotedType(x).type, 'int');
+        flow.whileStatement_conditionBegin({x}, {x});
+        h.promote(x, 'int');
+        expect(flow.promotedType(x), isNull);
+        h.function({x}, () {
+          flow.write(x);
+        });
+        flow.whileStatement_bodyBegin(_Statement(), _Expression());
+        flow.whileStatement_end();
+      });
+    });
+
     test('whileStatement_conditionBegin() handles not-yet-seen variables', () {
       var h = _Harness();
       var x = h.addVar('x', 'int?');
@@ -841,8 +1248,8 @@
       h.run((flow) {
         h.declare(y, initialized: true);
         h.promote(y, 'int');
-        flow.whileStatement_conditionBegin({x});
-        flow.write(x);
+        flow.whileStatement_conditionBegin({x}, {});
+        flow.initialize(x);
         flow.whileStatement_bodyBegin(_Statement(), _Expression());
         flow.whileStatement_end();
       });
@@ -853,7 +1260,7 @@
       var x = h.addVar('x', 'int?');
       h.run((flow) {
         h.declare(x, initialized: true);
-        flow.whileStatement_conditionBegin({});
+        flow.whileStatement_conditionBegin({}, {});
         flow.whileStatement_bodyBegin(_Statement(), h.notNull(x)());
         expect(flow.promotedType(x).type, 'int');
         flow.whileStatement_end();
@@ -873,7 +1280,7 @@
         h.declare(y, initialized: true);
         h.declare(z, initialized: true);
         var stmt = _Statement();
-        flow.whileStatement_conditionBegin({});
+        flow.whileStatement_conditionBegin({}, {});
         flow.whileStatement_bodyBegin(stmt, h.or(h.eqNull(x), h.eqNull(z))());
         h.if_(h.expr, () {
           h.promote(x, 'int');
@@ -893,7 +1300,7 @@
       h.run((flow) {
         h.declare(x, initialized: false);
         var trueCondition = _Expression();
-        flow.whileStatement_conditionBegin({x});
+        flow.whileStatement_conditionBegin({x}, {});
         flow.booleanLiteral(trueCondition, true);
         flow.whileStatement_bodyBegin(_Statement(), trueCondition);
         flow.whileStatement_end();
@@ -916,6 +1323,38 @@
         flow.ifStatement_end(false);
       });
     });
+
+    test('Promotions do not occur when a variable is write-captured', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'Object');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.function({x}, () {});
+        h.promote(x, 'int');
+        expect(flow.promotedType(x), isNull);
+      });
+    });
+
+    test('Promotion cancellation of write-captured vars survives join', () {
+      var h = _Harness();
+      var x = h.addVar('x', 'Object');
+      h.run((flow) {
+        h.declare(x, initialized: true);
+        h.ifElse(h.expr, () {
+          h.function({x}, () {});
+        }, () {
+          // Promotion should work here because the write capture is in the
+          // other branch.
+          h.promote(x, 'int');
+          expect(flow.promotedType(x).type, 'int');
+        });
+        // But the promotion should be cancelled now, after the join.
+        expect(flow.promotedType(x), isNull);
+        // And further attempts to promote should fail due to the write capture.
+        h.promote(x, 'int');
+        expect(flow.promotedType(x), isNull);
+      });
+    });
   });
 
   group('State', () {
@@ -972,7 +1411,7 @@
         expect(s2.reachable, true);
         _Type.allowComparisons(() {
           expect(s2.variableInfo,
-              {intQVar: VariableModel<_Type>(_Type('int'), false)});
+              {intQVar: VariableModel<_Type>(_Type('int'), false, false)});
         });
       });
 
@@ -1008,7 +1447,7 @@
         expect(s2.reachable, true);
         _Type.allowComparisons(() {
           expect(s2.variableInfo,
-              {objectQVar: VariableModel<_Type>(_Type('int'), false)});
+              {objectQVar: VariableModel<_Type>(_Type('int'), false, false)});
         });
       });
     });
@@ -1025,7 +1464,7 @@
         var s1 = FlowModel<_Var, _Type>(true);
         var s2 = s1.write(objectQVar);
         expect(s2.reachable, true);
-        expect(s2.infoFor(objectQVar), VariableModel<_Type>(null, true));
+        expect(s2.infoFor(objectQVar), VariableModel<_Type>(null, true, false));
       });
 
       test('un-promotes', () {
@@ -1036,7 +1475,8 @@
         expect(s1.variableInfo, contains(objectQVar));
         var s2 = s1.write(objectQVar);
         expect(s2.reachable, true);
-        expect(s2.variableInfo, {objectQVar: VariableModel<_Type>(null, true)});
+        expect(s2.variableInfo,
+            {objectQVar: VariableModel<_Type>(null, true, false)});
       });
     });
 
@@ -1054,7 +1494,8 @@
         var s2 = s1.markNonNullable(h, intQVar);
         expect(s2.reachable, true);
         _Type.allowComparisons(() {
-          expect(s2.infoFor(intQVar), VariableModel(_Type('int'), false));
+          expect(
+              s2.infoFor(intQVar), VariableModel(_Type('int'), false, false));
         });
       });
 
@@ -1074,7 +1515,7 @@
         expect(s2.reachable, true);
         _Type.allowComparisons(() {
           expect(s2.variableInfo,
-              {objectQVar: VariableModel<_Type>(_Type('int'), false)});
+              {objectQVar: VariableModel<_Type>(_Type('int'), false, false)});
         });
       });
     });
@@ -1084,21 +1525,36 @@
         var h = _Harness();
         var s1 =
             FlowModel<_Var, _Type>(true).promote(h, objectQVar, _Type('int'));
-        var s2 = s1.removePromotedAll([intQVar]);
+        var s2 = s1.removePromotedAll([intQVar], []);
         expect(s2, same(s1));
       });
 
-      test('changed', () {
+      test('written', () {
         var h = _Harness();
         var s1 = FlowModel<_Var, _Type>(true)
             .promote(h, objectQVar, _Type('int'))
             .promote(h, intQVar, _Type('int'));
-        var s2 = s1.removePromotedAll([intQVar]);
+        var s2 = s1.removePromotedAll([intQVar], []);
         expect(s2.reachable, true);
         _Type.allowComparisons(() {
           expect(s2.variableInfo, {
-            objectQVar: VariableModel<_Type>(_Type('int'), false),
-            intQVar: VariableModel<_Type>(null, false)
+            objectQVar: VariableModel<_Type>(_Type('int'), false, false),
+            intQVar: VariableModel<_Type>(null, false, false)
+          });
+        });
+      });
+
+      test('write captured', () {
+        var h = _Harness();
+        var s1 = FlowModel<_Var, _Type>(true)
+            .promote(h, objectQVar, _Type('int'))
+            .promote(h, intQVar, _Type('int'));
+        var s2 = s1.removePromotedAll([], [intQVar]);
+        expect(s2.reachable, true);
+        _Type.allowComparisons(() {
+          expect(s2.variableInfo, {
+            objectQVar: VariableModel<_Type>(_Type('int'), false, false),
+            intQVar: VariableModel<_Type>(null, false, true)
           });
         });
       });
@@ -1131,6 +1587,23 @@
         expect(result.infoFor(d).assigned, false);
       });
 
+      test('write captured', () {
+        var h = _Harness();
+        var a = _Var('a', _Type('int'));
+        var b = _Var('b', _Type('int'));
+        var c = _Var('c', _Type('int'));
+        var d = _Var('d', _Type('int'));
+        var s0 = FlowModel<_Var, _Type>(true);
+        // In s1, a and b are write captured.  In s2, a and c are.
+        var s1 = s0.removePromotedAll([a, b], [a, b]);
+        var s2 = s0.removePromotedAll([a, c], [a, c]);
+        var result = s1.restrict(h, s2, Set());
+        expect(result.infoFor(a).writeCaptured, true);
+        expect(result.infoFor(b).writeCaptured, true);
+        expect(result.infoFor(c).writeCaptured, true);
+        expect(result.infoFor(d).writeCaptured, false);
+      });
+
       test('promotion', () {
         void _check(String thisType, String otherType, bool unsafe,
             String expectedType) {
@@ -1178,12 +1651,15 @@
   group('join', () {
     var x = _Var('x', null);
     var y = _Var('y', null);
+    var z = _Var('y', null);
+    var w = _Var('y', null);
     var intType = _Type('int');
     var intQType = _Type('int?');
     var stringType = _Type('String');
     const emptyMap = <Null, VariableModel<Null>>{};
 
-    VariableModel<_Type> model(_Type type) => VariableModel<_Type>(type, true);
+    VariableModel<_Type> model(_Type type) =>
+        VariableModel<_Type>(type, true, false);
 
     group('without input reuse', () {
       test('promoted with unpromoted', () {
@@ -1259,6 +1735,52 @@
         var join21 = FlowModel.joinVariableInfo(h, p2, p1);
         _Type.allowComparisons(() => expect(join21, {x: model(intQType)}));
       });
+
+      test('assigned', () {
+        var h = _Harness();
+        var p1 = {
+          x: model(intQType).write(),
+          y: model(intQType).write(),
+          z: model(intQType),
+          w: model(intQType)
+        };
+        var p2 = {
+          x: model(intQType).write(),
+          y: model(intQType),
+          z: model(intQType).write(),
+          w: model(intQType)
+        };
+        var joined = FlowModel.joinVariableInfo(h, p1, p2);
+        _Type.allowComparisons(() => expect(joined, {
+              x: model(intQType).write(),
+              y: model(intQType).write(),
+              z: model(intQType).write(),
+              w: model(intQType)
+            }));
+      });
+
+      test('write captured', () {
+        var h = _Harness();
+        var p1 = {
+          x: model(intQType).writeCapture(),
+          y: model(intQType).writeCapture(),
+          z: model(intQType),
+          w: model(intQType)
+        };
+        var p2 = {
+          x: model(intQType).writeCapture(),
+          y: model(intQType),
+          z: model(intQType).writeCapture(),
+          w: model(intQType)
+        };
+        var joined = FlowModel.joinVariableInfo(h, p1, p2);
+        _Type.allowComparisons(() => expect(joined, {
+              x: model(intQType).writeCapture(),
+              y: model(intQType).writeCapture(),
+              z: model(intQType).writeCapture(),
+              w: model(intQType)
+            }));
+      });
     });
   });
 }
@@ -1287,20 +1809,35 @@
 
 class _Expression {}
 
-class _Harness
-    implements
-        NodeOperations<_Expression>,
-        TypeOperations<_Var, _Type>,
-        FunctionBodyAccess<_Var> {
+class _Harness implements TypeOperations<_Var, _Type> {
   FlowAnalysis<_Statement, _Expression, _Var, _Type> _flow;
 
+  final List<_Var> _variablesWrittenAnywhere = [];
+
+  final List<_Var> _variablesCapturedAnywhere = [];
+
   /// Returns a [LazyExpression] representing an expression with now special
   /// flow analysis semantics.
   LazyExpression get expr => () => _Expression();
 
-  _Var addVar(String name, String type) {
+  LazyExpression get nullLiteral => () {
+        var expr = _Expression();
+        _flow.nullLiteral(expr);
+        return expr;
+      };
+
+  _Var addVar(String name, String type,
+      {bool hasWrites: false, bool isCaptured: false}) {
     assert(_flow == null);
-    return _Var(name, _Type(type));
+    var v = _Var(name, _Type(type));
+    if (hasWrites) {
+      _variablesWrittenAnywhere.add(v);
+    }
+    if (isCaptured) {
+      assert(hasWrites);
+      _variablesCapturedAnywhere.add(v);
+    }
+    return v;
   }
 
   /// Given two [LazyExpression]s, produces a new [LazyExpression] representing
@@ -1328,11 +1865,12 @@
   }
 
   FlowAnalysis<_Statement, _Expression, _Var, _Type> createFlow() =>
-      FlowAnalysis<_Statement, _Expression, _Var, _Type>(this, this, this);
+      FlowAnalysis<_Statement, _Expression, _Var, _Type>(
+          this, _variablesWrittenAnywhere, _variablesCapturedAnywhere);
 
   void declare(_Var v, {@required bool initialized}) {
     if (initialized) {
-      _flow.write(v);
+      _flow.initialize(v);
     }
   }
 
@@ -1340,12 +1878,35 @@
   /// [variable].
   LazyExpression eqNull(_Var variable) {
     return () {
+      var varExpr = _Expression();
+      _flow.variableRead(varExpr, variable);
+      _flow.equalityOp_rightBegin(varExpr);
+      var nullExpr = _Expression();
+      _flow.nullLiteral(nullExpr);
       var expr = _Expression();
-      _flow.conditionEqNull(expr, variable, notEqual: false);
+      _flow.equalityOp_end(expr, nullExpr, notEqual: false);
       return expr;
     };
   }
 
+  /// Creates a [LazyExpression] representing an equality check between two
+  /// other expressions.
+  LazyExpression notEqual(LazyExpression lhs, LazyExpression rhs) {
+    return () {
+      var expr = _Expression();
+      _flow.equalityOp_rightBegin(lhs());
+      _flow.equalityOp_end(expr, rhs(), notEqual: true);
+      return expr;
+    };
+  }
+
+  /// Invokes flow analysis of a nested function.
+  void function(Iterable<_Var> writeCaptured, void body()) {
+    _flow.functionExpression_begin(writeCaptured);
+    body();
+    _flow.functionExpression_end();
+  }
+
   /// Invokes flow analysis of an `if` statement with no `else` part.
   void if_(LazyExpression cond, void ifTrue()) {
     _flow.ifStatement_thenBegin(cond());
@@ -1359,7 +1920,7 @@
     ifTrue();
     _flow.ifStatement_elseBegin();
     ifFalse();
-    _flow.ifStatement_end(false);
+    _flow.ifStatement_end(true);
   }
 
   /// Creates a [LazyExpression] representing an `is!` check, checking whether
@@ -1373,17 +1934,6 @@
   }
 
   @override
-  bool isPotentiallyMutatedInClosure(_Var variable) {
-    // TODO(paulberry): make tests where this returns true
-    return false;
-  }
-
-  @override
-  bool isPotentiallyMutatedInScope(_Var variable) {
-    throw UnimplementedError('TODO(paulberry)');
-  }
-
-  @override
   bool isSameType(_Type type1, _Type type2) {
     return type1.type == type2.type;
   }
@@ -1408,12 +1958,27 @@
     return _subtypes[query] ?? fail('Unknown subtype query: $query');
   }
 
+  /// Creates a [LazyExpression] representing an `is` check, checking whether
+  /// [variable] has the given [type].
+  LazyExpression isType(_Var variable, String type) {
+    return () {
+      var expr = _Expression();
+      _flow.isExpression_end(expr, variable, false, _Type(type));
+      return expr;
+    };
+  }
+
   /// Creates a [LazyExpression] representing a `!= null` check performed on
   /// [variable].
   LazyExpression notNull(_Var variable) {
     return () {
+      var varExpr = _Expression();
+      _flow.variableRead(varExpr, variable);
+      _flow.equalityOp_rightBegin(varExpr);
+      var nullExpr = _Expression();
+      _flow.nullLiteral(nullExpr);
       var expr = _Expression();
-      _flow.conditionEqNull(expr, variable, notEqual: true);
+      _flow.equalityOp_end(expr, nullExpr, notEqual: true);
       return expr;
     };
   }
@@ -1429,6 +1994,15 @@
     };
   }
 
+  /// Creates a [LazyExpression] representing a parenthesized subexpression.
+  LazyExpression parenthesized(LazyExpression inner) {
+    return () {
+      var expr = _Expression();
+      _flow.parenthesizedExpression(expr, inner());
+      return expr;
+    };
+  }
+
   /// Causes [variable] to be promoted to [type].
   void promote(_Var variable, String type) {
     if_(isNotType(variable, type), _flow.handleExit);
@@ -1451,10 +2025,12 @@
     _flow.finish();
   }
 
-  @override
-  _Expression unwrapParenthesized(_Expression node) {
-    // TODO(paulberry): test cases where this matters
-    return node;
+  LazyExpression variableRead(_Var variable) {
+    return () {
+      var expr = _Expression();
+      _flow.variableRead(expr, variable);
+      return expr;
+    };
   }
 
   @override
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 b7aeac8..be1e524 100644
--- a/pkg/front_end/test/fasta/generator_to_string_test.dart
+++ b/pkg/front_end/test/fasta/generator_to_string_test.dart
@@ -26,17 +26,16 @@
 
 import 'package:kernel/target/targets.dart' show NoneTarget, TargetFlags;
 
+import 'package:front_end/src/fasta/builder/type_declaration_builder.dart';
+import 'package:front_end/src/fasta/builder/prefix_builder.dart';
+import 'package:front_end/src/fasta/builder/type_variable_builder.dart';
+
 import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;
 
 import 'package:front_end/src/fasta/dill/dill_target.dart' show DillTarget;
 
 import 'package:front_end/src/fasta/kernel/kernel_builder.dart'
-    show
-        TypeVariableBuilder,
-        LoadLibraryBuilder,
-        PrefixBuilder,
-        TypeDeclarationBuilder,
-        UnlinkedDeclaration;
+    show LoadLibraryBuilder, UnlinkedDeclaration;
 
 import 'package:front_end/src/fasta/kernel/kernel_target.dart'
     show KernelTarget;
diff --git a/pkg/front_end/test/fasta/type_promotion_look_ahead_test.dart b/pkg/front_end/test/fasta/type_promotion_look_ahead_test.dart
index e707a31..d51c54d 100644
--- a/pkg/front_end/test/fasta/type_promotion_look_ahead_test.dart
+++ b/pkg/front_end/test/fasta/type_promotion_look_ahead_test.dart
@@ -7,7 +7,7 @@
 import 'package:front_end/src/base/processed_options.dart'
     show ProcessedOptions;
 
-import 'package:front_end/src/fasta/builder/declaration.dart';
+import 'package:front_end/src/fasta/builder/builder.dart';
 
 import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;
 
diff --git a/pkg/front_end/test/fasta/types/dill_hierachy_test.dart b/pkg/front_end/test/fasta/types/dill_hierachy_test.dart
index 56053fa..21fc07d 100644
--- a/pkg/front_end/test/fasta/types/dill_hierachy_test.dart
+++ b/pkg/front_end/test/fasta/types/dill_hierachy_test.dart
@@ -18,6 +18,8 @@
 import "package:front_end/src/base/processed_options.dart"
     show ProcessedOptions;
 
+import "package:front_end/src/fasta/builder/class_builder.dart";
+
 import "package:front_end/src/fasta/compiler_context.dart" show CompilerContext;
 
 import "package:front_end/src/fasta/dill/dill_loader.dart" show DillLoader;
@@ -25,7 +27,7 @@
 import "package:front_end/src/fasta/dill/dill_target.dart" show DillTarget;
 
 import "package:front_end/src/fasta/kernel/kernel_builder.dart"
-    show ClassHierarchyBuilder, ClassBuilder;
+    show ClassHierarchyBuilder;
 
 import "package:front_end/src/fasta/ticker.dart" show Ticker;
 
diff --git a/pkg/front_end/test/fasta/types/fasta_legacy_upper_bound_test.dart b/pkg/front_end/test/fasta/types/fasta_legacy_upper_bound_test.dart
index 289f047..1a5e9af 100644
--- a/pkg/front_end/test/fasta/types/fasta_legacy_upper_bound_test.dart
+++ b/pkg/front_end/test/fasta/types/fasta_legacy_upper_bound_test.dart
@@ -14,6 +14,8 @@
 import "package:front_end/src/base/processed_options.dart"
     show ProcessedOptions;
 
+import "package:front_end/src/fasta/builder/class_builder.dart";
+
 import "package:front_end/src/fasta/compiler_context.dart" show CompilerContext;
 
 import "package:front_end/src/fasta/dill/dill_loader.dart" show DillLoader;
@@ -21,7 +23,7 @@
 import "package:front_end/src/fasta/dill/dill_target.dart" show DillTarget;
 
 import "package:front_end/src/fasta/kernel/kernel_builder.dart"
-    show ClassHierarchyBuilder, ClassBuilder;
+    show ClassHierarchyBuilder;
 
 import "package:front_end/src/fasta/ticker.dart" show Ticker;
 
diff --git a/pkg/front_end/test/fasta/types/fasta_types_test.dart b/pkg/front_end/test/fasta/types/fasta_types_test.dart
index 5d3659ad..4a8c9b5 100644
--- a/pkg/front_end/test/fasta/types/fasta_types_test.dart
+++ b/pkg/front_end/test/fasta/types/fasta_types_test.dart
@@ -16,6 +16,8 @@
 import "package:front_end/src/base/processed_options.dart"
     show ProcessedOptions;
 
+import "package:front_end/src/fasta/builder/class_builder.dart";
+
 import "package:front_end/src/fasta/compiler_context.dart" show CompilerContext;
 
 import "package:front_end/src/fasta/dill/dill_loader.dart" show DillLoader;
@@ -23,7 +25,7 @@
 import "package:front_end/src/fasta/dill/dill_target.dart" show DillTarget;
 
 import "package:front_end/src/fasta/kernel/kernel_builder.dart"
-    show ClassHierarchyBuilder, ClassBuilder;
+    show ClassHierarchyBuilder;
 
 import "package:front_end/src/fasta/ticker.dart" show Ticker;
 import 'package:kernel/type_environment.dart';
diff --git a/pkg/front_end/test/fasta/types/kernel_type_parser_test.dart b/pkg/front_end/test/fasta/types/kernel_type_parser_test.dart
index d03b95d..3122299 100644
--- a/pkg/front_end/test/fasta/types/kernel_type_parser_test.dart
+++ b/pkg/front_end/test/fasta/types/kernel_type_parser_test.dart
@@ -25,16 +25,16 @@
 import "type_parser.dart" as type_parser show parse, parseTypeVariables;
 
 const String testSdk = """
-typedef Typedef<T> <S>(T) -> S;
-typedef VoidFunction () -> void;
-class DefaultTypes<S, T extends Object, U extends List<S>, V extends List<T>, W extends Comparable<W>, X extends (W) -> void, Y extends () -> W>;
-typedef TestDefaultTypes () -> DefaultTypes;
-typedef Id<T> T;
-typedef TestSorting ({int c, int b, int a}) -> void;
-class Super implements Comparable<Sub>;
+typedef Typedef<T> <S>(T*) ->* S*;
+typedef VoidFunction () ->* void;
+class DefaultTypes<S, T extends Object*, U extends List<S*>*, V extends List<T*>*, W extends Comparable<W*>*, X extends (W*) ->* void, Y extends () ->* W*>;
+typedef TestDefaultTypes () ->* DefaultTypes*;
+typedef Id<T> T*;
+typedef TestSorting ({int* c, int* b, int* a}) ->* void;
+class Super implements Comparable<Sub*>;
 class Sub extends Super;
-class FBound<T extends FBound<T>>;
-class MixinApplication extends Object with FBound<MixinApplication>;
+class FBound<T extends FBound<T*>*>;
+class MixinApplication extends Object with FBound<MixinApplication*>;
 """;
 
 const String expectedSdk = """
@@ -43,14 +43,14 @@
 
 typedef Typedef<T extends self::Object* = dynamic> = <S extends self::Object* = dynamic>(T*) →* S*;
 typedef VoidFunction = () →* void;
-typedef TestDefaultTypes = () →* self::DefaultTypes<dynamic, self::Object, self::List<dynamic>, self::List<self::Object>, self::Comparable<dynamic>, (<BottomType>) → void, () → self::Comparable<dynamic>>;
+typedef TestDefaultTypes = () →* self::DefaultTypes<dynamic, self::Object*, self::List<dynamic>*, self::List<self::Object*>*, self::Comparable<dynamic>*, (<BottomType>) →* void, () →* self::Comparable<dynamic>*>*;
 typedef Id<T extends self::Object* = dynamic> = T*;
-typedef TestSorting = ({a: self::int, b: self::int, c: self::int}) →* void;
+typedef TestSorting = ({a: self::int*, b: self::int*, c: self::int*}) →* void;
 class Object {
 }
 class Comparable<T extends self::Object* = dynamic> extends self::Object {
 }
-class num extends self::Object implements self::Comparable<self::num> {
+class num extends self::Object implements self::Comparable<self::num*> {
 }
 class int extends self::num {
 }
@@ -72,15 +72,15 @@
 }
 class bool extends self::Object {
 }
-class DefaultTypes<S extends self::Object* = dynamic, T extends self::Object = self::Object, U extends self::List<self::DefaultTypes::S*> = self::List<dynamic>, V extends self::List<self::DefaultTypes::T> = self::List<self::Object>, W extends self::Comparable<self::DefaultTypes::W> = self::Comparable<dynamic>, X extends (self::DefaultTypes::W) → void = (<BottomType>) → void, Y extends () → self::DefaultTypes::W = () → self::Comparable<dynamic>> extends self::Object {
+class DefaultTypes<S extends self::Object* = dynamic, T extends self::Object* = self::Object*, U extends self::List<self::DefaultTypes::S*>* = self::List<dynamic>*, V extends self::List<self::DefaultTypes::T*>* = self::List<self::Object*>*, W extends self::Comparable<self::DefaultTypes::W*>* = self::Comparable<dynamic>*, X extends (self::DefaultTypes::W*) →* void = (<BottomType>) →* void, Y extends () →* self::DefaultTypes::W* = () →* self::Comparable<dynamic>*> extends self::Object {
 }
-class Super extends self::Object implements self::Comparable<self::Sub> {
+class Super extends self::Object implements self::Comparable<self::Sub*> {
 }
 class Sub extends self::Super {
 }
-class FBound<T extends self::FBound<self::FBound::T> = self::FBound<dynamic>> extends self::Object {
+class FBound<T extends self::FBound<self::FBound::T*>* = self::FBound<dynamic>*> extends self::Object {
 }
-class MixinApplication = self::Object with self::FBound<self::MixinApplication> {
+class MixinApplication = self::Object with self::FBound<self::MixinApplication*> {
 }
 """;
 
diff --git a/pkg/front_end/test/fasta/types/mock_sdk.dart b/pkg/front_end/test/fasta/types/mock_sdk.dart
index d4a937b..606ee4d 100644
--- a/pkg/front_end/test/fasta/types/mock_sdk.dart
+++ b/pkg/front_end/test/fasta/types/mock_sdk.dart
@@ -5,11 +5,11 @@
 const String mockSdk = """
 class Object;
 class Comparable<T>;
-class num implements Comparable<num>;
+class num implements Comparable<num*>;
 class int extends num;
 class double extends num;
 class Iterable<T>;
-class List<T> extends Iterable<T>;
+class List<T> extends Iterable<T*>;
 class Future<T>;
 class FutureOr<T>;
 class Null;
diff --git a/pkg/front_end/test/fasta/types/shared_type_tests.dart b/pkg/front_end/test/fasta/types/shared_type_tests.dart
index 2210802..4a01bd2 100644
--- a/pkg/front_end/test/fasta/types/shared_type_tests.dart
+++ b/pkg/front_end/test/fasta/types/shared_type_tests.dart
@@ -32,159 +32,165 @@
   E extend(String typeParameters);
 
   void run() {
-    isSubtype('int', 'num');
-    isSubtype('int', 'Comparable<num>');
-    isSubtype('int', 'Comparable<Object>');
-    isSubtype('int', 'Object');
-    isSubtype('double', 'num');
+    isSubtype('int*', 'num*');
+    isSubtype('int*', 'Comparable<num*>*');
+    isSubtype('int*', 'Comparable<Object*>*');
+    isSubtype('int*', 'Object*');
+    isSubtype('double*', 'num*');
 
-    isNotSubtype('int', 'double');
-    isNotSubtype('int', 'Comparable<int>');
-    isNotSubtype('int', 'Iterable<int>');
-    isNotSubtype('Comparable<int>', 'Iterable<int>');
+    isNotSubtype('int*', 'double*');
+    isNotSubtype('int*', 'Comparable<int*>*');
+    isNotSubtype('int*', 'Iterable<int*>*');
+    isNotSubtype('Comparable<int*>*', 'Iterable<int*>*');
 
-    isSubtype('List<int>', 'List<int>');
-    isSubtype('List<int>', 'Iterable<int>');
-    isSubtype('List<int>', 'List<num>');
-    isSubtype('List<int>', 'Iterable<num>');
-    isSubtype('List<int>', 'List<Object>');
-    isSubtype('List<int>', 'Iterable<Object>');
-    isSubtype('List<int>', 'Object');
-    isSubtype('List<int>', 'List<Comparable<Object>>');
-    isSubtype('List<int>', 'List<Comparable<num>>');
-    isSubtype('List<int>', 'List<Comparable<Comparable<num>>>');
+    isSubtype('List<int*>*', 'List<int*>*');
+    isSubtype('List<int*>*', 'Iterable<int*>*');
+    isSubtype('List<int*>*', 'List<num*>*');
+    isSubtype('List<int*>*', 'Iterable<num*>*');
+    isSubtype('List<int*>*', 'List<Object*>*');
+    isSubtype('List<int*>*', 'Iterable<Object*>*');
+    isSubtype('List<int*>*', 'Object*');
+    isSubtype('List<int*>*', 'List<Comparable<Object*>*>*');
+    isSubtype('List<int*>*', 'List<Comparable<num*>*>*');
+    isSubtype('List<int*>*', 'List<Comparable<Comparable<num*>*>*>*');
 
-    isNotSubtype('List<int>', 'List<double>');
-    isNotSubtype('List<int>', 'Iterable<double>');
-    isNotSubtype('List<int>', 'Comparable<int>');
-    isNotSubtype('List<int>', 'List<Comparable<int>>');
-    isNotSubtype('List<int>', 'List<Comparable<Comparable<int>>>');
+    isNotSubtype('List<int*>*', 'List<double*>*');
+    isNotSubtype('List<int*>*', 'Iterable<double*>*');
+    isNotSubtype('List<int*>*', 'Comparable<int*>*');
+    isNotSubtype('List<int*>*', 'List<Comparable<int*>*>*');
+    isNotSubtype('List<int*>*', 'List<Comparable<Comparable<int*>*>*>*');
 
-    isSubtype('(num) -> num', '(int) -> num');
-    isSubtype('(num) -> int', '(num) -> num');
-    isSubtype('(num) -> int', '(int) -> num');
-    isNotSubtype('(int) -> int', '(num) -> num');
-    isSubtype('Null', '(int) -> num');
+    isSubtype('(num*) ->* num*', '(int*) ->* num*');
+    isSubtype('(num*) ->* int*', '(num*) ->* num*');
+    isSubtype('(num*) ->* int*', '(int*) ->* num*');
+    isNotSubtype('(int*) ->* int*', '(num*) ->* num*');
+    isSubtype('Null?', '(int*) ->* num*');
 
-    isSubtype('(num) -> (num) -> num', '(num) -> (int) -> num');
-    isNotSubtype('(num) -> (int) -> int', '(num) -> (num) -> num');
+    isSubtype('(num*) ->* (num*) ->* num*', '(num*) ->* (int*) ->* num*');
+    isNotSubtype('(num*) ->* (int*) ->* int*', '(num*) ->* (num*) ->* num*');
 
-    isSubtype('({num x}) -> num', '({int x}) -> num'); // named parameters
-    isSubtype('(num, {num x}) -> num', '(int, {int x}) -> num');
-    isSubtype('({num x}) -> int', '({num x}) -> num');
-    isNotSubtype('({int x}) -> int', '({num x}) -> num');
+    isSubtype('({num* x}) ->* num*', '({int* x}) ->* num*'); // named parameters
+    isSubtype('(num*, {num* x}) ->* num*', '(int*, {int* x}) ->* num*');
+    isSubtype('({num* x}) ->* int*', '({num* x}) ->* num*');
+    isNotSubtype('({int* x}) ->* int*', '({num* x}) ->* num*');
 
-    isSubtype('<E>(E) -> int', '<E>(E) -> num'); // type parameters
-    isSubtype('<E>(num) -> E', '<E>(int) -> E');
-    isSubtype('<E>(E,num) -> E', '<E>(E,int) -> E');
-    isNotSubtype('<E>(E,num) -> E', '<E>(E,E) -> E');
+    isSubtype('<E>(E) ->* int*', '<E>(E) ->* num*'); // type parameters
+    isSubtype('<E>(num*) ->* E', '<E>(int*) ->* E');
+    isSubtype('<E>(E,num*) ->* E', '<E>(E,int*) ->* E');
+    isNotSubtype('<E>(E,num*) ->* E', '<E>(E,E) ->* E');
 
-    isSubtype('<E>(E) -> (E) -> E', '<F>(F) -> (F) -> F');
-    isSubtype('<E>(E, (int,E) -> E) -> E', '<E>(E, (int,E) -> E) -> E');
-    isSubtype('<E>(E, (int,E) -> E) -> E', '<E>(E, (num,E) -> E) -> E');
-    isNotSubtype('<E,F>(E) -> (F) -> E', '<E>(E) -> <F>(F) -> E');
-    isNotSubtype('<E,F>(E) -> (F) -> E', '<F,E>(E) -> (F) -> E');
+    isSubtype('<E>(E) ->* (E) ->* E', '<F>(F) ->* (F) ->* F');
+    isSubtype('<E>(E, (int*,E) ->* E) ->* E', '<E>(E, (int*,E) ->* E) ->* E');
+    isSubtype('<E>(E, (int*,E) ->* E) ->* E', '<E>(E, (num*,E) ->* E) ->* E');
+    isNotSubtype('<E,F>(E) ->* (F) ->* E', '<E>(E) ->* <F>(F) ->* E');
+    isNotSubtype('<E,F>(E) ->* (F) ->* E', '<F,E>(E) ->* (F) ->* E');
 
-    isNotSubtype('<E>(E,num) -> E', '<E extends num>(E,E) -> E');
-    isNotSubtype('<E extends num>(E) -> int', '<E extends int>(E) -> int');
-    isNotSubtype('<E extends num>(E) -> E', '<E extends int>(E) -> E');
-    isNotSubtype('<E extends num>(int) -> E', '<E extends int>(int) -> E');
-    isSubtype('<E extends num>(E) -> E', '<F extends num>(F) -> num');
-    isSubtype('<E extends int>(E) -> E', '<F extends int>(F) -> num');
-    isSubtype('<E extends int>(E) -> E', '<F extends int>(F) -> int');
-    isNotSubtype('<E>(int) -> int', '(int) -> int');
-    isNotSubtype('<E,F>(int) -> int', '<E>(int) -> int');
-
-    isSubtype('<E extends List<E>>(E) -> E', '<F extends List<F>>(F) -> F');
+    isNotSubtype('<E>(E,num*) ->* E', '<E extends num*>(E*,E*) ->* E*');
     isNotSubtype(
-        '<E extends Iterable<E>>(E) -> E', '<F extends List<F>>(F) -> F');
-    isNotSubtype('<E>(E,List<Object>) -> E', '<F extends List<F>>(F,F) -> F');
+        '<E extends num*>(E*) ->* int*', '<E extends int*>(E*) ->* int*');
+    isNotSubtype('<E extends num*>(E*) ->* E*', '<E extends int*>(E*) ->* E*');
     isNotSubtype(
-        '<E>(E,List<Object>) -> List<E>', '<F extends List<F>>(F,F) -> F');
-    isNotSubtype('<E>(E,List<Object>) -> int', '<F extends List<F>>(F,F) -> F');
-    isNotSubtype(
-        '<E>(E,List<Object>) -> E', '<F extends List<F>>(F,F) -> void');
+        '<E extends num*>(int*) ->* E*', '<E extends int*>(int*) ->* E*');
+    isSubtype('<E extends num*>(E*) ->* E*', '<F extends num*>(F*) ->* num*');
+    isSubtype('<E extends int*>(E*) ->* E*', '<F extends int*>(F*) ->* num*');
+    isSubtype('<E extends int*>(E*) ->* E*', '<F extends int*>(F*) ->* int*');
+    isNotSubtype('<E>(int*) ->* int*', '(int*) ->* int*');
+    isNotSubtype('<E,F>(int*) ->* int*', '<E>(int*) ->* int*');
 
-    isSubtype('int', 'FutureOr<int>');
-    isSubtype('int', 'FutureOr<num>');
-    isSubtype('Future<int>', 'FutureOr<int>');
-    isSubtype('Future<int>', 'FutureOr<num>');
-    isSubtype('Future<int>', 'FutureOr<Object>');
-    isSubtype('FutureOr<int>', 'FutureOr<int>');
-    isSubtype('FutureOr<int>', 'FutureOr<num>');
-    isSubtype('FutureOr<int>', 'Object');
-    isNotSubtype('int', 'FutureOr<double>');
-    isNotSubtype('FutureOr<double>', 'int');
-    isNotSubtype('FutureOr<int>', 'Future<num>');
-    isNotSubtype('FutureOr<int>', 'num');
-    isSubtype('Null', 'FutureOr<int>');
-    isSubtype('Null', 'Future<int>');
-    isSubtype('dynamic', 'FutureOr<dynamic>');
-    isNotSubtype('dynamic', 'FutureOr<String>');
-    isSubtype('void', 'FutureOr<void>');
-    isNotSubtype('void', 'FutureOr<String>');
-    isSubtype('E', 'FutureOr<E>', typeParameters: 'E');
-    isNotSubtype('E', 'FutureOr<String>', typeParameters: 'E');
-    isSubtype('() -> String', 'FutureOr<() -> void>');
-    isNotSubtype('() -> void', 'FutureOr<() -> String>');
-    isSubtype('FutureOr<int>', 'FutureOr<num>');
-    isNotSubtype('FutureOr<num>', 'FutureOr<int>');
-    isSubtype('T & int', 'FutureOr<num>', typeParameters: 'T');
-    isSubtype('T & Future<num>', 'FutureOr<num>', typeParameters: 'T');
-    isSubtype('T & Future<int>', 'FutureOr<num>', typeParameters: 'T');
+    isSubtype(
+        '<E extends List<E*>*>(E*) ->* E*', '<F extends List<F*>*>(F*) ->* F*');
+    isNotSubtype('<E extends Iterable<E*>*>(E*) ->* E*',
+        '<F extends List<F*>*>(F*) ->* F*');
+    isNotSubtype(
+        '<E>(E,List<Object*>*) ->* E*', '<F extends List<F*>*>(F*,F*) ->* F*');
+    isNotSubtype('<E>(E,List<Object*>*) ->* List<E>*',
+        '<F extends List<F*>*>(F*,F*) ->* F*');
+    isNotSubtype('<E>(E,List<Object*>*) ->* int*',
+        '<F extends List<F*>*>(F*,F*) ->* F*');
+    isNotSubtype(
+        '<E>(E,List<Object*>*) ->* E', '<F extends List<F*>*>(F*,F*) ->* void');
+
+    isSubtype('int*', 'FutureOr<int*>*');
+    isSubtype('int*', 'FutureOr<num*>*');
+    isSubtype('Future<int*>*', 'FutureOr<int*>*');
+    isSubtype('Future<int*>*', 'FutureOr<num*>*');
+    isSubtype('Future<int*>*', 'FutureOr<Object*>*');
+    isSubtype('FutureOr<int*>*', 'FutureOr<int*>*');
+    isSubtype('FutureOr<int*>*', 'FutureOr<num*>*');
+    isSubtype('FutureOr<int*>*', 'Object*');
+    isNotSubtype('int*', 'FutureOr<double*>*');
+    isNotSubtype('FutureOr<double*>*', 'int*');
+    isNotSubtype('FutureOr<int*>*', 'Future<num*>*');
+    isNotSubtype('FutureOr<int*>*', 'num*');
+    isSubtype('Null?', 'FutureOr<int*>*');
+    isSubtype('Null?', 'Future<int*>*');
+    isSubtype('dynamic', 'FutureOr<dynamic>*');
+    isNotSubtype('dynamic', 'FutureOr<String*>*');
+    isSubtype('void', 'FutureOr<void>*');
+    isNotSubtype('void', 'FutureOr<String*>*');
+    isSubtype('E', 'FutureOr<E>*', typeParameters: 'E');
+    isNotSubtype('E', 'FutureOr<String*>*', typeParameters: 'E');
+    isSubtype('() ->* String*', 'FutureOr<() ->* void>*');
+    isNotSubtype('() ->* void', 'FutureOr<() ->* String>*');
+    isSubtype('FutureOr<int*>*', 'FutureOr<num*>*');
+    isNotSubtype('FutureOr<num*>*', 'FutureOr<int*>*');
+    isSubtype('T & int*', 'FutureOr<num*>*', typeParameters: 'T');
+    isSubtype('T & Future<num*>*', 'FutureOr<num*>*', typeParameters: 'T');
+    isSubtype('T & Future<int*>*', 'FutureOr<num*>*', typeParameters: 'T');
     if (!skipFutureOrPromotion) {
-      isSubtype('T & FutureOr<int>', 'FutureOr<num>', typeParameters: 'T');
-      isSubtype('T & FutureOr<num>', 'FutureOr<num>', typeParameters: 'T');
-      isSubtype('T & String', 'FutureOr<num>', typeParameters: 'T extends int');
-      isSubtype('T & Future<String>', 'FutureOr<num>',
-          typeParameters: 'T extends Future<num>');
-      isSubtype('T & FutureOr<String>', 'FutureOr<num>',
-          typeParameters: 'T extends FutureOr<int>');
-      isSubtype('T & FutureOr<String>', 'FutureOr<num>',
-          typeParameters: 'T extends FutureOr<num>');
+      isSubtype('T & FutureOr<int*>*', 'FutureOr<num*>*', typeParameters: 'T');
+      isSubtype('T & FutureOr<num*>*', 'FutureOr<num*>*', typeParameters: 'T');
+      isSubtype('T* & String*', 'FutureOr<num*>*',
+          typeParameters: 'T extends int*');
+      isSubtype('T* & Future<String*>*', 'FutureOr<num*>*',
+          typeParameters: 'T extends Future<num*>*');
+      isSubtype('T* & FutureOr<String*>*', 'FutureOr<num*>*',
+          typeParameters: 'T extends FutureOr<int*>*');
+      isSubtype('T* & FutureOr<String*>*', 'FutureOr<num*>*',
+          typeParameters: 'T extends FutureOr<num*>*');
     }
-    isNotSubtype('T & num', 'FutureOr<int>', typeParameters: 'T');
-    isNotSubtype('T & Future<num>', 'FutureOr<int>', typeParameters: 'T');
-    isNotSubtype('T & FutureOr<num>', 'FutureOr<int>', typeParameters: 'T');
-    isNotSubtype('T & String', 'FutureOr<int>',
-        typeParameters: 'T extends num');
-    isNotSubtype('T & Future<String>', 'FutureOr<int>',
-        typeParameters: 'T extends Future<num>');
-    isNotSubtype('T & FutureOr<String>', 'FutureOr<int>',
-        typeParameters: 'T extends FutureOr<num>');
-    isSubtype('Id<int>', 'FutureOr<num>');
-    isNotSubtype('Id<num>', 'FutureOr<int>');
-    isSubtype('FutureOr<Object>', 'FutureOr<FutureOr<Object>>');
+    isNotSubtype('T & num*', 'FutureOr<int*>*', typeParameters: 'T');
+    isNotSubtype('T & Future<num*>*', 'FutureOr<int*>*', typeParameters: 'T');
+    isNotSubtype('T & FutureOr<num*>*', 'FutureOr<int*>*', typeParameters: 'T');
+    isNotSubtype('T* & String*', 'FutureOr<int*>*',
+        typeParameters: 'T extends num*');
+    isNotSubtype('T* & Future<String*>*', 'FutureOr<int*>*',
+        typeParameters: 'T extends Future<num*>*');
+    isNotSubtype('T* & FutureOr<String*>*', 'FutureOr<int*>*',
+        typeParameters: 'T extends FutureOr<num*>*');
+    isSubtype('Id<int*>*', 'FutureOr<num*>*');
+    isNotSubtype('Id<num*>*', 'FutureOr<int*>*');
+    isSubtype('FutureOr<Object*>*', 'FutureOr<FutureOr<Object*>*>*');
 
     // T & B <: T & A if B <: A
-    isSubtype('T & int', 'T & int', typeParameters: 'T');
-    isSubtype('T & int', 'T & num', typeParameters: 'T');
-    isSubtype('T & num', 'T & num', typeParameters: 'T');
-    isNotSubtype('T & num', 'T & int', typeParameters: 'T');
-    isSubtype('Null', 'T & num', typeParameters: 'T');
+    isSubtype('T & int*', 'T & int*', typeParameters: 'T');
+    isSubtype('T & int*', 'T & num*', typeParameters: 'T');
+    isSubtype('T & num*', 'T & num*', typeParameters: 'T');
+    isNotSubtype('T & num*', 'T & int*', typeParameters: 'T');
+    isSubtype('Null?', 'T & num*', typeParameters: 'T');
 
     // T & B <: T extends A if B <: A
     // (Trivially satisfied since promoted bounds are always a isSubtype of the
     // original bound)
-    isSubtype('T & int', 'T', typeParameters: 'T extends int');
-    isSubtype('T & int', 'T', typeParameters: 'T extends num');
-    isSubtype('T & num', 'T', typeParameters: 'T extends num');
+    isSubtype('T* & int*', 'T*', typeParameters: 'T extends int*');
+    isSubtype('T* & int*', 'T*', typeParameters: 'T extends num*');
+    isSubtype('T* & num*', 'T*', typeParameters: 'T extends num*');
 
     // T extends B <: T & A if B <: A
-    isSubtype('T', 'T & int', typeParameters: 'T extends int');
-    isSubtype('T', 'T & num', typeParameters: 'T extends int');
-    isSubtype('T', 'T & num', typeParameters: 'T extends num');
-    isNotSubtype('T', 'T & int', typeParameters: 'T extends num');
+    isSubtype('T*', 'T* & int*', typeParameters: 'T extends int*');
+    isSubtype('T*', 'T* & num*', typeParameters: 'T extends int*');
+    isSubtype('T*', 'T* & num*', typeParameters: 'T extends num*');
+    isNotSubtype('T*', 'T* & int*', typeParameters: 'T extends num*');
 
     // T extends A <: T extends A
-    isSubtype('T', 'T', typeParameters: 'T extends num');
+    isSubtype('T*', 'T*', typeParameters: 'T extends num*');
 
     isSubtype('T', 'T', typeParameters: 'T');
     isNotSubtype('S', 'T', typeParameters: 'S, T');
 
-    isSubtype('T', 'T', typeParameters: 'T extends Object');
-    isNotSubtype('S', 'T',
-        typeParameters: 'S extends Object, T extends Object');
+    isSubtype('T*', 'T*', typeParameters: 'T extends Object*');
+    isNotSubtype('S*', 'T*',
+        typeParameters: 'S extends Object*, T extends Object*');
 
     isSubtype('T', 'T', typeParameters: 'T extends dynamic');
     isNotSubtype('S', 'T',
@@ -195,64 +201,64 @@
     isSubtype('T', 'S', typeParameters: 'S, T extends S');
 
     // S & B <: A if B <: A, A is not S (or a promotion thereof)
-    isSubtype('S & int', 'int', typeParameters: 'S');
-    isSubtype('S & int', 'num', typeParameters: 'S');
-    isSubtype('S & num', 'num', typeParameters: 'S');
-    isNotSubtype('S & num', 'int', typeParameters: 'S');
-    isNotSubtype('S & num', 'T', typeParameters: 'S, T');
-    isNotSubtype('S & num', 'T & num', typeParameters: 'S, T');
+    isSubtype('S & int*', 'int*', typeParameters: 'S');
+    isSubtype('S & int*', 'num*', typeParameters: 'S');
+    isSubtype('S & num*', 'num*', typeParameters: 'S');
+    isNotSubtype('S & num*', 'int*', typeParameters: 'S');
+    isNotSubtype('S & num*', 'T', typeParameters: 'S, T');
+    isNotSubtype('S & num*', 'T & num*', typeParameters: 'S, T');
 
     // S extends B <: A if B <: A, A is not S (or a promotion thereof)
-    isSubtype('S', 'int', typeParameters: 'S extends int');
-    isSubtype('S', 'num', typeParameters: 'S extends int');
-    isSubtype('S', 'num', typeParameters: 'S extends num');
-    isNotSubtype('S', 'int', typeParameters: 'S extends num');
-    isNotSubtype('S', 'T', typeParameters: 'S extends num, T');
-    isNotSubtype('S', 'T & num', typeParameters: 'S extends num, T');
+    isSubtype('S*', 'int*', typeParameters: 'S extends int*');
+    isSubtype('S*', 'num*', typeParameters: 'S extends int*');
+    isSubtype('S*', 'num*', typeParameters: 'S extends num*');
+    isNotSubtype('S*', 'int*', typeParameters: 'S extends num*');
+    isNotSubtype('S*', 'T', typeParameters: 'S extends num*, T');
+    isNotSubtype('S*', 'T & num*', typeParameters: 'S extends num*, T');
 
-    isNotSubtype('dynamic', 'int');
-    isNotSubtype('void', 'int');
-    isNotSubtype('() -> int', 'int');
-    isNotSubtype('Typedef<Object>', 'int');
-    isSubtype('() -> int', 'Function');
-    isSubtype('() -> int', 'Object');
+    isNotSubtype('dynamic', 'int*');
+    isNotSubtype('void', 'int*');
+    isNotSubtype('() ->* int*', 'int*');
+    isNotSubtype('Typedef<Object*>*', 'int*');
+    isSubtype('() ->* int*', 'Function*');
+    isSubtype('() ->* int*', 'Object*');
 
-    isNotSubtype('Null', 'bottom');
-    isSubtype('Null', 'Object');
-    isSubtype('Null', 'void');
-    isSubtype('Null', 'dynamic');
-    isSubtype('Null', 'double');
-    isSubtype('Null', 'Comparable<Object>');
-    isSubtype('Null', 'Typedef<Object>');
-    isSubtype('Null', 'T', typeParameters: 'T');
+    isNotSubtype('Null?', 'bottom');
+    isSubtype('Null?', 'Object*');
+    isSubtype('Null?', 'void');
+    isSubtype('Null?', 'dynamic');
+    isSubtype('Null?', 'double*');
+    isSubtype('Null?', 'Comparable<Object*>*');
+    isSubtype('Null?', 'Typedef<Object*>*');
+    isSubtype('Null?', 'T', typeParameters: 'T extends Object*');
 
-    isSubtype('Null', 'Null');
+    isSubtype('Null?', 'Null?');
     isSubtype('bottom', 'bottom');
-    isSubtype('Object', 'Object');
-    isSubtype('Object', 'dynamic');
-    isSubtype('Object', 'void');
-    isSubtype('dynamic', 'Object');
+    isSubtype('Object*', 'Object*');
+    isSubtype('Object*', 'dynamic');
+    isSubtype('Object*', 'void');
+    isSubtype('dynamic', 'Object*');
     isSubtype('dynamic', 'dynamic');
     isSubtype('dynamic', 'void');
-    isSubtype('void', 'Object');
+    isSubtype('void', 'Object*');
     isSubtype('void', 'dynamic');
     isSubtype('void', 'void');
 
     // Check that the top types are equivalent.
-    isSubtype('<S extends Object, T extends void>(S, T) -> void',
-        '<U extends dynamic, V extends Object>(U, V) -> void');
+    isSubtype('<S extends Object*, T extends void>(S, T) ->* void',
+        '<U extends dynamic, V extends Object*>(U, V) ->* void');
 
     {
-      String f = '<T extends dynamic>() -> T';
-      String g = '<T extends Object>() -> T';
+      String f = '<T extends dynamic>() ->* T';
+      String g = '<T extends Object*>() ->* T*';
       isSubtype(f, g);
       isSubtype(g, f);
     }
 
     {
-      String h = '<T extends List<dynamic>>() -> T';
-      String i = '<T extends List<Object>>() -> T';
-      String j = '<T extends List<void>>() -> T';
+      String h = '<T extends List<dynamic>*>() ->* T*';
+      String i = '<T extends List<Object*>*>() ->* T*';
+      String j = '<T extends List<void>*>() ->* T*';
       isSubtype(h, i);
       isSubtype(h, j);
       isSubtype(i, h);
@@ -261,158 +267,168 @@
       isSubtype(j, i);
     }
 
-    isNotSubtype('dynamic', '() -> dynamic');
-    isNotSubtype('FutureOr<() -> void>', '() -> void');
-    isSubtype('T & () -> void', '() -> void', typeParameters: 'T');
-    isSubtype('T & () -> void', '() -> dynamic', typeParameters: 'T');
-    isSubtype('T & () -> void', '() -> Object', typeParameters: 'T');
+    isNotSubtype('dynamic', '() ->* dynamic');
+    isNotSubtype('FutureOr<() ->* void>*', '() ->* void');
+    isSubtype('T & () ->* void', '() ->* void', typeParameters: 'T');
+    isSubtype('T & () ->* void', '() ->* dynamic', typeParameters: 'T');
+    isSubtype('T & () ->* void', '() ->* Object*', typeParameters: 'T');
 
-    isSubtype('T & (void) -> void', '(void) -> void', typeParameters: 'T');
-    isSubtype('T & (void) -> void', '(dynamic) -> dynamic',
+    isSubtype('T & (void) ->* void', '(void) ->* void', typeParameters: 'T');
+    isSubtype('T & (void) ->* void', '(dynamic) ->* dynamic',
         typeParameters: 'T');
-    isSubtype('T & (void) -> void', '(Object) -> Object', typeParameters: 'T');
-
-    isSubtype('T & (void) -> void', '(void) -> void', typeParameters: 'T');
-    isSubtype('T & (void) -> void', '(Iterable<int>) -> dynamic',
+    isSubtype('T & (void) ->* void', '(Object*) ->* Object*',
         typeParameters: 'T');
-    isSubtype('T & (void) -> void', '(int) -> Object', typeParameters: 'T');
 
-    isNotSubtype('T & (void) -> void', '(int) -> int', typeParameters: 'T');
+    isSubtype('T & (void) ->* void', '(void) ->* void', typeParameters: 'T');
+    isSubtype('T & (void) ->* void', '(Iterable<int*>*) ->* dynamic',
+        typeParameters: 'T');
+    isSubtype('T & (void) ->* void', '(int*) ->* Object*', typeParameters: 'T');
 
-    isSubtype('T', '() -> void', typeParameters: 'T extends () -> void');
-    isNotSubtype('T', '() -> void', typeParameters: 'T');
-    isNotSubtype('Typedef<void>', '() -> void');
-    isSubtype('VoidFunction', '() -> void');
+    isNotSubtype('T & (void) ->* void', '(int*) ->* int*', typeParameters: 'T');
+
+    isSubtype('T*', '() ->* void', typeParameters: 'T extends () ->* void');
+    isNotSubtype('T', '() ->* void', typeParameters: 'T');
+    isNotSubtype('Typedef<void>*', '() ->* void');
+    isSubtype('VoidFunction*', '() ->* void');
     isNotSubtype(
-        'DefaultTypes<void, void, List<void>, List<void>, '
-            'int, (int) -> void, () -> int>',
-        '() -> void');
-    isNotSubtype('void', '() -> void');
+        'DefaultTypes<void, void, List<void>*, List<void>*, '
+            'int*, (int*) ->* void, () ->* int>*',
+        '() ->* void');
+    isNotSubtype('void', '() ->* void');
 
     isNotSubtype('dynamic', 'T', typeParameters: 'T');
-    isNotSubtype('Iterable<T>', 'T', typeParameters: 'T');
-    isNotSubtype('() -> void', 'T', typeParameters: 'T');
-    isNotSubtype('FutureOr<T>', 'T', typeParameters: 'T');
-    isSubtype('Id<T>', 'T', typeParameters: 'T');
-    isNotSubtype('VoidFunction', 'T', typeParameters: 'T extends () -> void');
+    isNotSubtype('Iterable<T>*', 'T', typeParameters: 'T');
+    isNotSubtype('() ->* void', 'T', typeParameters: 'T');
+    isNotSubtype('FutureOr<T>*', 'T', typeParameters: 'T');
+    isSubtype('Id<T>*', 'T', typeParameters: 'T');
+    isNotSubtype('VoidFunction*', 'T*',
+        typeParameters: 'T extends () ->* void');
     isNotSubtype('void', 'T', typeParameters: 'T extends void');
 
-    isSubtype('dynamic', 'Id<dynamic>');
-    isNotSubtype('dynamic', 'Id<int>');
-    isSubtype('() -> void', 'Id<() -> void>');
-    isNotSubtype('() -> void', 'Id<() -> int>');
-    isNotSubtype('FutureOr<() -> void>', 'Id<() -> void>');
-    isSubtype('FutureOr<() -> void>', 'Id<FutureOr<() -> void>>');
-    isSubtype('int', 'Id<int>');
-    isSubtype('T & () -> void', 'Id<() -> void>', typeParameters: 'T');
-    isSubtype('T & () -> void', 'Id<() -> dynamic>', typeParameters: 'T');
-    isSubtype('T & () -> void', 'Id<() -> Object>', typeParameters: 'T');
+    isSubtype('dynamic', 'Id<dynamic>*');
+    isNotSubtype('dynamic', 'Id<int*>*');
+    isSubtype('() ->* void', 'Id<() ->* void>*');
+    isNotSubtype('() ->* void', 'Id<() ->* int>*');
+    isNotSubtype('FutureOr<() ->* void>*', 'Id<() ->* void>*');
+    isSubtype('FutureOr<() ->* void>*', 'Id<FutureOr<() ->* void>*>*');
+    isSubtype('int*', 'Id<int*>*');
+    isSubtype('T & () ->* void', 'Id<() ->* void>*', typeParameters: 'T');
+    isSubtype('T & () ->* void', 'Id<() ->* dynamic>*', typeParameters: 'T');
+    isSubtype('T & () ->* void', 'Id<() ->* Object*>*', typeParameters: 'T');
 
-    isSubtype('T & (void) -> void', 'Id<(void) -> void>', typeParameters: 'T');
-    isSubtype('T & (void) -> void', 'Id<(dynamic) -> dynamic>',
+    isSubtype('T & (void) ->* void', 'Id<(void) ->* void>*',
         typeParameters: 'T');
-    isSubtype('T & (void) -> void', 'Id<(Object) -> Object>',
+    isSubtype('T & (void) ->* void', 'Id<(dynamic) ->* dynamic>*',
+        typeParameters: 'T');
+    isSubtype('T & (void) ->* void', 'Id<(Object*) ->* Object*>*',
         typeParameters: 'T');
 
-    isSubtype('T & (void) -> void', 'Id<(void) -> void>', typeParameters: 'T');
-    isSubtype('T & (void) -> void', 'Id<(Iterable<int>) -> dynamic>',
+    isSubtype('T & (void) ->* void', 'Id<(void) ->* void>*',
         typeParameters: 'T');
-    isSubtype('T & (void) -> void', 'Id<(int) -> Object>', typeParameters: 'T');
+    isSubtype('T & (void) ->* void', 'Id<(Iterable<int*>*) ->* dynamic>*',
+        typeParameters: 'T');
+    isSubtype('T & (void) ->* void', 'Id<(int*) ->* Object*>*',
+        typeParameters: 'T');
 
-    isNotSubtype('T & (void) -> void', 'Id<(int) -> int>', typeParameters: 'T');
+    isNotSubtype('T & (void) ->* void', 'Id<(int*) ->* int*>*',
+        typeParameters: 'T');
     isNotSubtype('dynamic', 'T & dynamic', typeParameters: 'T extends dynamic');
-    isNotSubtype('() -> T', 'T & () -> T', typeParameters: 'T');
+    isNotSubtype('() ->* T', 'T & () ->* T', typeParameters: 'T');
 
-    isNotSubtype('FutureOr<T & String>', 'T & String', typeParameters: 'T');
+    isNotSubtype('FutureOr<T & String*>*', 'T & String*', typeParameters: 'T');
 
-    isSubtype('Id<T & String>', 'T & String', typeParameters: 'T');
-    isSubtype('Id<T & String>', 'T', typeParameters: 'T');
-    isSubtype('Id<T & String>', 'String', typeParameters: 'T');
-    isNotSubtype('Id<T & String>', 'S & String', typeParameters: 'T, S');
+    isSubtype('Id<T & String*>*', 'T & String*', typeParameters: 'T');
+    isSubtype('Id<T & String*>*', 'T', typeParameters: 'T');
+    isSubtype('Id<T & String*>*', 'String*', typeParameters: 'T');
+    isNotSubtype('Id<T & String*>*', 'S & String*', typeParameters: 'T, S');
 
     isNotSubtype('void', 'T & void', typeParameters: 'T');
     isNotSubtype('void', 'T & void', typeParameters: 'T extends void');
 
-    isSubtype('T', 'Id<T>', typeParameters: 'T');
-    isSubtype('T', 'Id<Object>', typeParameters: 'T');
-    isNotSubtype('T', 'Id<Comparable<int>>', typeParameters: 'T');
-    isSubtype('T', 'Id<Comparable<int>>',
-        typeParameters: 'T extends Comparable<int>');
+    isSubtype('T', 'Id<T>*', typeParameters: 'T');
+    isSubtype('T', 'Id<Object*>*', typeParameters: 'T');
+    isNotSubtype('T', 'Id<Comparable<int*>*>*', typeParameters: 'T');
+    isSubtype('T*', 'Id<Comparable<int*>*>*',
+        typeParameters: 'T extends Comparable<int*>*');
 
-    isSubtype('Id<int>', 'Id<int>');
-    isSubtype('Id<int>', 'Id<Object>');
-    isNotSubtype('Id<Object>', 'Id<int>');
-    isSubtype('Id<() -> int>', 'Id<() -> int>');
-    isSubtype('Id<() -> int>', 'Id<() -> Object>');
-    isNotSubtype('Id<() -> Object>', 'Id<() -> int>');
+    isSubtype('Id<int*>*', 'Id<int*>*');
+    isSubtype('Id<int*>*', 'Id<Object*>*');
+    isNotSubtype('Id<Object*>*', 'Id<int*>*');
+    isSubtype('Id<() ->* int*>*', 'Id<() ->* int*>*');
+    isSubtype('Id<() ->* int*>*', 'Id<() ->* Object*>*');
+    isNotSubtype('Id<() ->* Object*>*', 'Id<() ->* int*>*');
 
-    isSubtype('void', 'Id<void>');
-    isNotSubtype('void', 'Id<Null>');
+    isSubtype('void', 'Id<void>*');
+    isNotSubtype('void', 'Id<Null?>*');
 
     // The following function type tests are derived from
     // ../../../../../tests/compiler/dart2js/model/subtype_test.dart.
-    isSubtype("() -> int", 'Function');
-    isNotSubtype('Function', "() -> int");
+    isSubtype("() ->* int*", 'Function*');
+    isNotSubtype('Function*', "() ->* int*");
 
-    isSubtype("() -> dynamic", "() -> dynamic");
-    isSubtype("() -> dynamic", "() -> void");
-    isSubtype("() -> void", "() -> dynamic");
+    isSubtype("() ->* dynamic", "() ->* dynamic");
+    isSubtype("() ->* dynamic", "() ->* void");
+    isSubtype("() ->* void", "() ->* dynamic");
 
-    isSubtype("() -> int", "() -> void");
-    isNotSubtype("() -> void", "() -> int");
-    isSubtype("() -> void", "() -> void");
-    isSubtype("() -> int", "() -> int");
-    isSubtype("() -> int", "() -> Object");
-    isNotSubtype("() -> int", "() -> double");
-    isNotSubtype("() -> int", "(int) -> void");
-    isNotSubtype("() -> void", "(int) -> int");
-    isNotSubtype("() -> void", "(int) -> void");
-    isSubtype("(int) -> int", "(int) -> int");
-    isSubtype("(Object) -> int", "(int) -> Object");
-    isNotSubtype("(int) -> int", "(double) -> int");
-    isNotSubtype("() -> int", "(int) -> int");
-    isNotSubtype("(int) -> int", "(int, int) -> int");
-    isNotSubtype("(int, int) -> int", "(int) -> int");
-    isNotSubtype("(() -> void) -> void", "((int) -> void) -> void");
-    isNotSubtype("((int) -> void) -> void", "(() -> void) -> void");
+    isSubtype("() ->* int*", "() ->* void");
+    isNotSubtype("() ->* void", "() ->* int*");
+    isSubtype("() ->* void", "() ->* void");
+    isSubtype("() ->* int*", "() ->* int*");
+    isSubtype("() ->* int*", "() ->* Object*");
+    isNotSubtype("() ->* int*", "() ->* double*");
+    isNotSubtype("() ->* int*", "(int*) ->* void");
+    isNotSubtype("() ->* void", "(int*) ->* int*");
+    isNotSubtype("() ->* void", "(int*) ->* void");
+    isSubtype("(int*) ->* int*", "(int*) ->* int*");
+    isSubtype("(Object*) ->* int*", "(int*) ->* Object*");
+    isNotSubtype("(int*) ->* int*", "(double*) ->* int*");
+    isNotSubtype("() ->* int*", "(int*) ->* int*");
+    isNotSubtype("(int*) ->* int*", "(int*, int*) ->* int*");
+    isNotSubtype("(int*, int*) ->* int*", "(int*) ->* int*");
+    isNotSubtype("(() ->* void) ->* void", "((int*) ->* void) ->* void");
+    isNotSubtype("((int*) ->* void) ->* void", "(() ->* void) ->* void");
 
     // Optional positional parameters.
-    isSubtype("([int]) -> void", "() -> void");
-    isSubtype("([int]) -> void", "(int) -> void");
-    isNotSubtype("(int) -> void", "([int]) -> void");
-    isSubtype("([int]) -> void", "([int]) -> void");
-    isSubtype("([Object]) -> void", "([int]) -> void");
-    isNotSubtype("([int]) -> void", "([Object]) -> void");
-    isSubtype("(int, [int]) -> void", "(int) -> void");
-    isSubtype("(int, [int]) -> void", "(int, [int]) -> void");
-    isNotSubtype("(int) -> void", "([int]) -> void");
-    isSubtype("([int, int]) -> void", "(int) -> void");
-    isSubtype("([int, int]) -> void", "(int, [int]) -> void");
-    isNotSubtype("([int, int]) -> void", "(int, [int, int]) -> void");
-    isSubtype("([int, int, int]) -> void", "(int, [int, int]) -> void");
-    isNotSubtype("([int]) -> void", "(double) -> void");
-    isNotSubtype("([int]) -> void", "([int, int]) -> void");
-    isSubtype("([int, int]) -> void", "([int]) -> void");
-    isSubtype("([Object, int]) -> void", "([int]) -> void");
+    isSubtype("([int*]) ->* void", "() ->* void");
+    isSubtype("([int*]) ->* void", "(int*) ->* void");
+    isNotSubtype("(int*) ->* void", "([int*]) ->* void");
+    isSubtype("([int*]) ->* void", "([int*]) ->* void");
+    isSubtype("([Object*]) ->* void", "([int*]) ->* void");
+    isNotSubtype("([int*]) ->* void", "([Object*]) ->* void");
+    isSubtype("(int*, [int*]) ->* void", "(int*) ->* void");
+    isSubtype("(int*, [int*]) ->* void", "(int*, [int*]) ->* void");
+    isNotSubtype("(int*) ->* void", "([int*]) ->* void");
+    isSubtype("([int*, int*]) ->* void", "(int*) ->* void");
+    isSubtype("([int*, int*]) ->* void", "(int*, [int*]) ->* void");
+    isNotSubtype("([int*, int*]) ->* void", "(int*, [int*, int*]) ->* void");
+    isSubtype("([int*, int*, int*]) ->* void", "(int*, [int*, int*]) ->* void");
+    isNotSubtype("([int*]) ->* void", "(double*) ->* void");
+    isNotSubtype("([int*]) ->* void", "([int*, int*]) ->* void");
+    isSubtype("([int*, int*]) ->* void", "([int*]) ->* void");
+    isSubtype("([Object*, int*]) ->* void", "([int*]) ->* void");
 
     // Optional named parameters.
-    isSubtype("({int a}) -> void", "() -> void");
-    isNotSubtype("({int a}) -> void", "(int) -> void");
-    isNotSubtype("(int) -> void", "({int a}) -> void");
-    isSubtype("({int a}) -> void", "({int a}) -> void");
-    isNotSubtype("({int a}) -> void", "({int b}) -> void");
-    isSubtype("({Object a}) -> void", "({int a}) -> void");
-    isNotSubtype("({int a}) -> void", "({Object a}) -> void");
-    isSubtype("(int, {int a}) -> void", "(int, {int a}) -> void");
-    isNotSubtype("({int a}) -> void", "({double a}) -> void");
-    isNotSubtype("({int a}) -> void", "({int a, int b}) -> void");
-    isSubtype("({int a, int b}) -> void", "({int a}) -> void");
-    isSubtype("({int a, int b, int c}) -> void", "({int a, int c}) -> void");
-    isSubtype("({int c, int b, int a}) -> void", "({int a, int c}) -> void");
-    isSubtype("({int a, int b, int c}) -> void", "({int b, int c}) -> void");
-    isSubtype("({int c, int b, int a}) -> void", "({int b, int c}) -> void");
-    isSubtype("({int a, int b, int c}) -> void", "({int c}) -> void");
-    isSubtype("({int c, int b, int a}) -> void", "({int c}) -> void");
+    isSubtype("({int* a}) ->* void", "() ->* void");
+    isNotSubtype("({int* a}) ->* void", "(int*) ->* void");
+    isNotSubtype("(int*) ->* void", "({int* a}) ->* void");
+    isSubtype("({int* a}) ->* void", "({int* a}) ->* void");
+    isNotSubtype("({int* a}) ->* void", "({int* b}) ->* void");
+    isSubtype("({Object* a}) ->* void", "({int* a}) ->* void");
+    isNotSubtype("({int* a}) ->* void", "({Object* a}) ->* void");
+    isSubtype("(int*, {int* a}) ->* void", "(int*, {int* a}) ->* void");
+    isNotSubtype("({int* a}) ->* void", "({double* a}) ->* void");
+    isNotSubtype("({int* a}) ->* void", "({int* a, int* b}) ->* void");
+    isSubtype("({int* a, int* b}) ->* void", "({int* a}) ->* void");
+    isSubtype(
+        "({int* a, int* b, int* c}) ->* void", "({int* a, int* c}) ->* void");
+    isSubtype(
+        "({int* c, int* b, int* a}) ->* void", "({int* a, int* c}) ->* void");
+    isSubtype(
+        "({int* a, int* b, int* c}) ->* void", "({int* b, int* c}) ->* void");
+    isSubtype(
+        "({int* c, int* b, int* a}) ->* void", "({int* b, int* c}) ->* void");
+    isSubtype("({int* a, int* b, int* c}) ->* void", "({int* c}) ->* void");
+    isSubtype("({int* c, int* b, int* a}) ->* void", "({int* c}) ->* void");
 
     // Parsing of nullable and legacy types.
     isSubtype("int?", "int?");
diff --git a/pkg/front_end/test/fasta/types/subtypes_benchmark.dart b/pkg/front_end/test/fasta/types/subtypes_benchmark.dart
index c46d75a..d999e06 100644
--- a/pkg/front_end/test/fasta/types/subtypes_benchmark.dart
+++ b/pkg/front_end/test/fasta/types/subtypes_benchmark.dart
@@ -28,6 +28,8 @@
 import "package:front_end/src/base/processed_options.dart"
     show ProcessedOptions;
 
+import "package:front_end/src/fasta/builder/class_builder.dart";
+
 import "package:front_end/src/fasta/compiler_context.dart" show CompilerContext;
 
 import "package:front_end/src/fasta/dill/dill_loader.dart" show DillLoader;
@@ -35,7 +37,7 @@
 import "package:front_end/src/fasta/dill/dill_target.dart" show DillTarget;
 
 import "package:front_end/src/fasta/kernel/kernel_builder.dart"
-    show ClassHierarchyBuilder, ClassBuilder;
+    show ClassHierarchyBuilder;
 
 import "package:front_end/src/fasta/ticker.dart" show Ticker;
 
diff --git a/pkg/front_end/test/fasta/unlinked_scope_test.dart b/pkg/front_end/test/fasta/unlinked_scope_test.dart
index d9eea6f..40c5e2e 100644
--- a/pkg/front_end/test/fasta/unlinked_scope_test.dart
+++ b/pkg/front_end/test/fasta/unlinked_scope_test.dart
@@ -17,15 +17,14 @@
 import 'package:front_end/src/base/processed_options.dart'
     show ProcessedOptions;
 
+import 'package:front_end/src/fasta/builder/procedure_builder.dart';
+
 import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;
 
 import 'package:front_end/src/fasta/dill/dill_target.dart' show DillTarget;
 
 import 'package:front_end/src/fasta/kernel/body_builder.dart' show BodyBuilder;
 
-import 'package:front_end/src/fasta/kernel/kernel_builder.dart'
-    show ProcedureBuilder;
-
 import 'package:front_end/src/fasta/kernel/kernel_target.dart'
     show KernelTarget;
 
@@ -58,7 +57,7 @@
             null);
 
   ProcedureBuilder mockProcedure(String name) {
-    return new ProcedureBuilder(null, 0, null, name, null, null,
+    return new ProcedureBuilderImpl(null, 0, null, name, null, null,
         ProcedureKind.Getter, this, -1, -1, -1, -1);
   }
 }
diff --git a/pkg/front_end/test/flow_analysis/definite_assignment/data/initialization.dart b/pkg/front_end/test/flow_analysis/definite_assignment/data/initialization.dart
new file mode 100644
index 0000000..5b0058b
--- /dev/null
+++ b/pkg/front_end/test/flow_analysis/definite_assignment/data/initialization.dart
@@ -0,0 +1,33 @@
+// 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 tests in this file exercise various kinds of constructs that initialize a
+// variable at its declaration site.  We verify that the variable is considered
+// definitely assigned by the initialization.
+
+parameter(int a) {
+  a;
+}
+
+localParameter() {
+  localFunction(int a) {
+    a;
+  }
+
+  (int b) {
+    b;
+  };
+}
+
+localVariable() {
+  Object a = 1;
+  a;
+}
+
+catchParameters() {
+  try {} on Object catch (e, st) {
+    e;
+    st;
+  }
+}
diff --git a/pkg/front_end/test/flow_analysis/nullability/data/null_check.dart b/pkg/front_end/test/flow_analysis/nullability/data/null_check.dart
new file mode 100644
index 0000000..e18296b
--- /dev/null
+++ b/pkg/front_end/test/flow_analysis/nullability/data/null_check.dart
@@ -0,0 +1,8 @@
+// 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.
+
+void bang_promotes(int? x) {
+  x!;
+  /*nonNullable*/ x;
+}
diff --git a/pkg/front_end/test/flow_analysis/type_promotion/data/assert.dart b/pkg/front_end/test/flow_analysis/type_promotion/data/assert.dart
new file mode 100644
index 0000000..5695e66
--- /dev/null
+++ b/pkg/front_end/test/flow_analysis/type_promotion/data/assert.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.
+
+void assertStatement(Object x) {
+  assert((x is int ? /*int*/ x : throw 'foo') == 0);
+  // TODO(paulberry): should not be promoted because the assertion won't execute
+  // in release mode.  See https://github.com/dart-lang/sdk/issues/38761.
+  /*int*/ x;
+}
diff --git a/pkg/front_end/test/flow_analysis/type_promotion/data/assigned_anywhere.dart b/pkg/front_end/test/flow_analysis/type_promotion/data/assigned_anywhere.dart
new file mode 100644
index 0000000..f1cd041
--- /dev/null
+++ b/pkg/front_end/test/flow_analysis/type_promotion/data/assigned_anywhere.dart
@@ -0,0 +1,168 @@
+// 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 verifies that for various ways of defining functions, we properly
+// determine which set of variables are potentially assigned anywhere within the
+// function, and suppress promotions inside closures.
+
+bool f(Object x) => true;
+
+topLevel_function(Object x, Object y) {
+  if (x is int && y is int) {
+    /*int*/ x;
+    /*int*/ y;
+    () {
+      /*int*/ x;
+      y;
+    };
+  }
+  y = 'foo';
+}
+
+topLevel_function_arrow(Object x, Object y) => (x is int && y is int)
+    ? [
+        /*int*/ x,
+        /*int*/ y,
+        () {
+          /*int*/ x;
+          y;
+        }
+      ]
+    : (y = 'foo');
+
+void topLevel_setter(Object x) {
+  Object y = f(0);
+  if (x is int && y is int) {
+    /*int*/ x;
+    /*int*/ y;
+    () {
+      /*int*/ x;
+      y;
+    };
+  }
+  y = 'foo';
+}
+
+void topLevel_setter_arrow(Object y) => (y is int)
+    ? [
+        /*int*/ y,
+        () {
+          y;
+        }
+      ]
+    : (y = 'foo');
+
+get topLevel_getter {
+  Object x = f(0);
+  Object y = f(0);
+  if (x is int && y is int) {
+    /*int*/ x;
+    /*int*/ y;
+    () {
+      /*int*/ x;
+      y;
+    };
+  }
+  y = 'foo';
+  return 0;
+}
+
+class C {
+  C(Object x);
+
+  C.constructor(Object x, Object y) {
+    if (x is int && y is int) {
+      /*int*/ x;
+      /*int*/ y;
+      () {
+        /*int*/ x;
+        y;
+      };
+    }
+    y = 'foo';
+  }
+
+  factory C.constructor_arrow(Object x, Object y) => C((x is int && y is int)
+      ? [
+          /*int*/ x,
+          /*int*/ y,
+          () {
+            /*int*/ x;
+            y;
+          }
+        ]
+      : (y = 'foo'));
+
+  C.constructor_semicolon(Object x, Object y)
+      : assert(f((x is int && y is int)
+            ? [
+                /*int*/ x,
+                /*int*/ y,
+                () {
+                  /*int*/ x;
+                  y;
+                }
+              ]
+            : (y = 'foo')));
+
+  method(Object x, Object y) {
+    if (x is int && y is int) {
+      /*int*/ x;
+      /*int*/ y;
+      () {
+        /*int*/ x;
+        y;
+      };
+    }
+    y = 'foo';
+  }
+
+  method_arrow(Object x, Object y) => (x is int && y is int)
+      ? [
+          /*int*/ x,
+          /*int*/ y,
+          () {
+            /*int*/ x;
+            y;
+          }
+        ]
+      : (y = 'foo');
+
+  void setter(Object x) {
+    Object y = f(0);
+    if (x is int && y is int) {
+      /*int*/ x;
+      /*int*/ y;
+      () {
+        /*int*/ x;
+        y;
+      };
+    }
+    y = 'foo';
+  }
+
+  void setter_arrow(Object y) => (y is int)
+      ? [
+          /*int*/ y,
+          () {
+            y;
+          }
+        ]
+      : (y = 'foo');
+
+  get getter {
+    Object x = f(0);
+    Object y = f(0);
+    if (x is int && y is int) {
+      /*int*/ x;
+      /*int*/ y;
+      () {
+        /*int*/ x;
+        y;
+      };
+    }
+    y = 'foo';
+    return 0;
+  }
+}
diff --git a/pkg/front_end/test/flow_analysis/type_promotion/data/constructor_initializer.dart b/pkg/front_end/test/flow_analysis/type_promotion/data/constructor_initializer.dart
new file mode 100644
index 0000000..4d37319
--- /dev/null
+++ b/pkg/front_end/test/flow_analysis/type_promotion/data/constructor_initializer.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 {
+  int y;
+  C.normalInitializer(Object x) : y = x is int ? /*int*/ x : throw 'foo' {
+    /*int*/ x;
+  }
+  C.assertInitializer(Object x)
+      : y = 0,
+        assert((x is int ? /*int*/ x : throw 'foo') == 0) {
+    // TODO(paulberry): should not be promoted because the assertion won't
+    // execute in release mode.  See
+    // https://github.com/dart-lang/sdk/issues/38761
+    /*int*/ x;
+  }
+}
diff --git a/pkg/front_end/test/flow_analysis/type_promotion/data/function_expression.dart b/pkg/front_end/test/flow_analysis/type_promotion/data/function_expression.dart
index 98cbd9a..6b7f51d 100644
--- a/pkg/front_end/test/flow_analysis/type_promotion/data/function_expression.dart
+++ b/pkg/front_end/test/flow_analysis/type_promotion/data/function_expression.dart
@@ -7,6 +7,14 @@
     if (x is String) {
       /*String*/ x;
     }
+  }
+}
+
+void isType_mutatedInClosure() {
+  void g(Object x) {
+    if (x is String) {
+      /*String*/ x;
+    }
     x = 42;
   }
 }
diff --git a/pkg/front_end/test/flow_analysis/type_promotion/data/initialization.dart b/pkg/front_end/test/flow_analysis/type_promotion/data/initialization.dart
new file mode 100644
index 0000000..099a022
--- /dev/null
+++ b/pkg/front_end/test/flow_analysis/type_promotion/data/initialization.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.
+
+// The tests in this file exercise various kinds of constructs that initialize a
+// variable at its declaration site.  We verify that the variable is not
+// considered "written to" for purposes of defeating type promotions inside
+// closures.
+
+parameter(Object a) {
+  if (a is int) {
+    () {
+      /*int*/ a;
+    };
+  }
+}
+
+localParameter() {
+  localFunction(Object a) {
+    if (a is int) {
+      () {
+        /*int*/ a;
+      };
+    }
+  }
+
+  (Object b) {
+    if (b is int) {
+      () {
+        /*int*/ b;
+      };
+    }
+  };
+}
+
+localVariable() {
+  Object a = 1;
+  if (a is int) {
+    () {
+      /*int*/ a;
+    };
+  }
+}
+
+class MyStackTrace implements StackTrace {
+  noSuchMethod(invocation) => super.noSuchMethod(invocation);
+}
+
+catchParameters() {
+  try {} on Object catch (e, st) {
+    if (e is int) {
+      () {
+        /*int*/ e;
+      };
+    }
+    if (st is MyStackTrace) {
+      () {
+        /*MyStackTrace*/ st;
+      };
+    }
+  }
+}
diff --git a/pkg/front_end/test/flow_analysis/type_promotion/data/inside_closure.dart b/pkg/front_end/test/flow_analysis/type_promotion/data/inside_closure.dart
new file mode 100644
index 0000000..27821bd
--- /dev/null
+++ b/pkg/front_end/test/flow_analysis/type_promotion/data/inside_closure.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.
+
+void nested_closures(Function([dynamic]) f) {
+  void inner(Object x) {
+    if (x is String) {
+      f();
+      // TODO(paulberry): x should be promoted here.
+      // See https://github.com/dart-lang/sdk/issues/38791
+      x;
+    }
+    f(() {
+      if (x is String) {
+        f();
+        x;
+      }
+      x = 0;
+    });
+    if (x is String) {
+      f();
+      x;
+    }
+  }
+}
diff --git a/pkg/front_end/test/flow_analysis/type_promotion/data/write_capture.dart b/pkg/front_end/test/flow_analysis/type_promotion/data/write_capture.dart
new file mode 100644
index 0000000..b5170c8
--- /dev/null
+++ b/pkg/front_end/test/flow_analysis/type_promotion/data/write_capture.dart
@@ -0,0 +1,283 @@
+// 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.
+
+T f<T>(T x, void callback()) {
+  callback();
+  return x;
+}
+
+doLoop(Object a, Object b, Object c) {
+  do {
+    if (a is int) a;
+    if (b is int) b;
+    if (c is int) /*int*/ c;
+    f(0, () {
+      a = '';
+    });
+  } while (f(true, () {
+    b = '';
+  }));
+  f(0, () {
+    c = '';
+  });
+}
+
+forLoop(Object a, Object b, Object c, Object d, Object e) {
+  for (var x = f(0, () {
+    a = '';
+  });
+      f(true, () {
+    b = '';
+  });
+      f(0, () {
+    c = '';
+  })) {
+    if (a is int) a;
+    if (b is int) b;
+    if (c is int) c;
+    if (d is int) d;
+    if (e is int) /*int*/ e;
+    f(0, () {
+      d = '';
+    });
+  }
+  f(0, () {
+    e = '';
+  });
+}
+
+forEachLoop(Object a, Object b, Object c) {
+  for (var x in f([], () {
+    a = '';
+  })) {
+    if (a is int) a;
+    if (b is int) b;
+    if (c is int) /*int*/ c;
+    f(0, () {
+      b = '';
+    });
+  }
+  f(0, () {
+    c = '';
+  });
+}
+
+forElement(Object a, Object b, Object c, Object d, Object e) {
+  [
+    for (var x = f(0, () {
+      a = '';
+    });
+        f(true, () {
+      b = '';
+    });
+        f(0, () {
+      c = '';
+    }))
+      [
+        a is int ? a : null,
+        b is int ? b : null,
+        c is int ? c : null,
+        d is int ? d : null,
+        e is int ? /*int*/ e : null,
+        f(0, () {
+          d = '';
+        })
+      ]
+  ];
+  f(0, () {
+    e = '';
+  });
+}
+
+forEachElement(Object a, Object b, Object c) {
+  [
+    for (var x in () {
+      a = '';
+      return [];
+    }())
+      [
+        a is int ? a : null,
+        b is int ? b : null,
+        c is int ? /*int*/ c : null,
+        f(0, () {
+          b = '';
+        })
+      ]
+  ];
+  f(0, () {
+    c = '';
+  });
+}
+
+switchWithoutLabels(Object a, Object b, Object c) {
+  switch (f(0, () {
+    a = '';
+  })) {
+    case 0:
+      if (a is int) a;
+      if (b is int) /*int*/ b;
+      if (c is int) /*int*/ c;
+      f(0, () {
+        b = '';
+      });
+      break;
+  }
+  f(0, () {
+    c = '';
+  });
+}
+
+switchWithLabels(Object a, Object b, Object c) {
+  switch (f(0, () {
+    a = '';
+  })) {
+    L:
+    case 0:
+      if (a is int) a;
+      if (b is int) b;
+      if (c is int) /*int*/ c;
+      f(0, () {
+        b = '';
+      });
+      break;
+  }
+  f(0, () {
+    c = '';
+  });
+}
+
+tryCatch(Object a, Object b, Object c) {
+  try {
+    if (a is int) /*int*/ a;
+    if (b is int) /*int*/ b;
+    if (c is int) /*int*/ c;
+    f(0, () {
+      a = '';
+    });
+    return;
+  } catch (_) {
+    if (a is int) a;
+    if (b is int) /*int*/ b;
+    if (c is int) /*int*/ c;
+    f(0, () {
+      b = '';
+    });
+  }
+  if (a is int) a;
+  if (b is int) b;
+  if (c is int) /*int*/ c;
+  f(0, () {
+    c = '';
+  });
+}
+
+tryFinally(Object a, Object b, Object c) {
+  try {
+    if (a is int) /*int*/ a;
+    if (b is int) /*int*/ b;
+    if (c is int) /*int*/ c;
+    f(0, () {
+      a = '';
+    });
+  } finally {
+    if (a is int) a;
+    if (b is int) /*int*/ b;
+    if (c is int) /*int*/ c;
+    f(0, () {
+      b = '';
+    });
+  }
+  if (a is int) a;
+  if (b is int) b;
+  if (c is int) /*int*/ c;
+  f(0, () {
+    c = '';
+  });
+}
+
+whileLoop(Object a, Object b, Object c) {
+  while (f(true, () {
+    a = '';
+  })) {
+    if (a is int) a;
+    if (b is int) b;
+    if (c is int) /*int*/ c;
+    f(0, () {
+      b = '';
+    });
+  }
+  f(0, () {
+    c = '';
+  });
+}
+
+localFunction(Object a, Object b, Object c) {
+  if (a is! int) return;
+  if (b is! int) return;
+  if (c is! int) return;
+  /*int*/ a;
+  /*int*/ b;
+  /*int*/ c;
+  foo() {
+    /*int*/ a;
+    b;
+    c;
+    if (b is int) /*int*/ b;
+    if (c is int) c;
+  }
+
+  b = '';
+  /*int*/ a;
+  b;
+  /*int*/ c;
+  if (b is int) /*int*/ b;
+  bar() {
+    /*int*/ a;
+    b;
+    c;
+    if (b is int) /*int*/ b;
+    if (c is int) c;
+    c = '';
+  }
+
+  /*int*/ a;
+  b;
+  c;
+  if (b is int) /*int*/ b;
+  if (c is int) c;
+}
+
+closure(Object a, Object b, Object c) {
+  if (a is! int) return;
+  if (b is! int) return;
+  if (c is! int) return;
+  /*int*/ a;
+  /*int*/ b;
+  /*int*/ c;
+  f(0, () {
+    /*int*/ a;
+    b;
+    c;
+    if (b is int) /*int*/ b;
+    if (c is int) c;
+  });
+  b = '';
+  /*int*/ a;
+  b;
+  /*int*/ c;
+  if (b is int) /*int*/ b;
+  f(0, () {
+    /*int*/ a;
+    b;
+    c;
+    if (b is int) /*int*/ b;
+    if (c is int) c;
+    c = '';
+  });
+  /*int*/ a;
+  b;
+  c;
+  if (b is int) /*int*/ b;
+  if (c is int) c;
+}
diff --git a/pkg/front_end/test/incremental_load_from_dill_test.dart b/pkg/front_end/test/incremental_load_from_dill_test.dart
index 9013baa..903c589 100644
--- a/pkg/front_end/test/incremental_load_from_dill_test.dart
+++ b/pkg/front_end/test/incremental_load_from_dill_test.dart
@@ -8,11 +8,6 @@
 
 import 'package:expect/expect.dart' show Expect;
 
-import 'package:front_end/src/base/processed_options.dart'
-    show ProcessedOptions;
-
-import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;
-
 import 'package:front_end/src/api_prototype/compiler_options.dart'
     show CompilerOptions;
 
@@ -22,16 +17,31 @@
 import "package:front_end/src/api_prototype/memory_file_system.dart"
     show MemoryFileSystem;
 
+import 'package:front_end/src/base/processed_options.dart'
+    show ProcessedOptions;
+
 import 'package:front_end/src/compute_platform_binaries_location.dart'
     show computePlatformBinariesLocation;
 
+import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;
+
+import 'package:front_end/src/fasta/fasta_codes.dart'
+    show DiagnosticMessageFromJson, FormattedMessage;
+
 import 'package:front_end/src/fasta/incremental_compiler.dart'
     show IncrementalCompiler;
 
+import 'package:front_end/src/fasta/incremental_serializer.dart'
+    show IncrementalSerializer;
+
+import 'package:front_end/src/fasta/kernel/utils.dart' show ByteSink;
+
 import 'package:front_end/src/fasta/severity.dart' show Severity;
 
 import 'package:kernel/binary/ast_from_binary.dart' show BinaryBuilder;
 
+import 'package:kernel/binary/ast_to_binary.dart' show BinaryPrinter;
+
 import 'package:kernel/kernel.dart'
     show
         Class,
@@ -59,9 +69,6 @@
 
 import "incremental_utils.dart" as util;
 
-import 'package:front_end/src/fasta/fasta_codes.dart'
-    show DiagnosticMessageFromJson, FormattedMessage;
-
 import 'utils/io_utils.dart' show computeRepoDir;
 
 main([List<String> arguments = const []]) =>
@@ -129,12 +136,19 @@
         );
         break;
       case "newworld":
-        keys.removeAll(["worlds", "modules", "omitPlatform", "target"]);
+        keys.removeAll([
+          "worlds",
+          "modules",
+          "omitPlatform",
+          "target",
+          "incrementalSerialization"
+        ]);
         await newWorldTest(
           map["worlds"],
           map["modules"],
           map["omitPlatform"],
           map["target"],
+          map["incrementalSerialization"],
         );
         break;
       default:
@@ -272,8 +286,8 @@
   return moduleResult;
 }
 
-Future<Null> newWorldTest(
-    List worlds, Map modules, bool omitPlatform, String targetName) async {
+Future<Null> newWorldTest(List worlds, Map modules, bool omitPlatform,
+    String targetName, bool incrementalSerialization) async {
   final Uri sdkRoot = computePlatformBinariesLocation(forceBuildDir: true);
   final Uri base = Uri.parse("org-dartlang-test:///");
   final Uri sdkSummary = base.resolve("vm_platform_strong.dill");
@@ -288,6 +302,7 @@
   Map<String, String> sourceFiles;
   CompilerOptions options;
   TestIncrementalCompiler compiler;
+  IncrementalSerializer incrementalSerializer;
 
   Map<String, List<int>> moduleData;
   Map<String, Component> moduleComponents;
@@ -335,6 +350,7 @@
         }
       }
     }
+
     bool brandNewWorld = true;
     if (world["worldType"] == "updated") {
       brandNewWorld = false;
@@ -426,12 +442,24 @@
     bool outlineOnly = world["outlineOnly"] == true;
     bool skipOutlineBodyCheck = world["skipOutlineBodyCheck"] == true;
     if (brandNewWorld) {
+      if (incrementalSerialization == true) {
+        incrementalSerializer = new IncrementalSerializer();
+      }
       if (world["fromComponent"] == true) {
         compiler = new TestIncrementalCompiler.fromComponent(
-            options, entries.first, newestWholeComponent, outlineOnly);
+            options,
+            entries.first,
+            (modulesToUse != null) ? sdk : newestWholeComponent,
+            outlineOnly,
+            incrementalSerializer);
       } else {
-        compiler = new TestIncrementalCompiler(
-            options, entries.first, initializeFrom, outlineOnly);
+        compiler = new TestIncrementalCompiler(options, entries.first,
+            initializeFrom, outlineOnly, incrementalSerializer);
+
+        if (modulesToUse != null) {
+          throw "You probably shouldn't do this! "
+              "Any modules will have another sdk loaded!";
+        }
       }
     }
 
@@ -559,6 +587,13 @@
       throw "Expected that initializedFromDill would be "
           "$expectInitializeFromDill but was ${compiler.initializedFromDill}";
     }
+
+    if (incrementalSerialization == true && compiler.initializedFromDill) {
+      Expect.isTrue(compiler.initializedIncrementalSerializer);
+    } else {
+      Expect.isFalse(compiler.initializedIncrementalSerializer);
+    }
+
     if (world["checkInvalidatedFiles"] != false) {
       Set<Uri> filteredInvalidated =
           compiler.getFilteredInvalidatedImportUrisForTesting(invalidated);
@@ -575,14 +610,21 @@
         Expect.isNull(world["expectedInvalidatedUri"]);
       }
     }
+    List<int> incrementalSerializationBytes = checkIncrementalSerialization(
+        incrementalSerialization, component, incrementalSerializer, world);
 
-    if (!noFullComponent) {
-      Set<String> prevFormattedErrors = formattedErrors.toSet();
-      Set<String> prevFormattedWarnings = formattedWarnings.toSet();
+    Set<String> prevFormattedErrors = formattedErrors.toSet();
+    Set<String> prevFormattedWarnings = formattedWarnings.toSet();
+
+    clearPrevErrorsEtc() {
       gotError = false;
       formattedErrors.clear();
       gotWarning = false;
       formattedWarnings.clear();
+    }
+
+    if (!noFullComponent) {
+      clearPrevErrorsEtc();
       Component component2 = await compiler.computeDelta(
           entryPoints: entries,
           fullComponent: true,
@@ -593,28 +635,23 @@
       print("*****\n\ncomponent2:\n"
           "${componentToStringSdkFiltered(component2)}\n\n\n");
       checkIsEqual(newestWholeComponentData, thisWholeComponent);
-      if (prevFormattedErrors.length != formattedErrors.length) {
-        Expect.fail("Previously had ${prevFormattedErrors.length} errors, "
-            "now had ${formattedErrors.length}.\n\n"
-            "Before:\n"
-            "${prevFormattedErrors.join("\n")}"
-            "\n\n"
-            "Now:\n"
-            "${formattedErrors.join("\n")}");
+      checkErrorsAndWarnings(prevFormattedErrors, formattedErrors,
+          prevFormattedWarnings, formattedWarnings);
+
+      List<int> incrementalSerializationBytes2 = checkIncrementalSerialization(
+          incrementalSerialization, component2, incrementalSerializer, world);
+
+      if ((incrementalSerializationBytes == null &&
+              incrementalSerializationBytes2 != null) ||
+          (incrementalSerializationBytes != null &&
+              incrementalSerializationBytes2 == null)) {
+        throw "Incremental serialization gave results in one instance, "
+            "but not another.";
       }
-      if ((prevFormattedErrors.toSet()..removeAll(formattedErrors))
-          .isNotEmpty) {
-        Expect.fail("Previously got error messages $prevFormattedErrors, "
-            "now had ${formattedErrors}.");
-      }
-      if (prevFormattedWarnings.length != formattedWarnings.length) {
-        Expect.fail("Previously had ${prevFormattedWarnings.length} errors, "
-            "now had ${formattedWarnings.length}.");
-      }
-      if ((prevFormattedWarnings.toSet()..removeAll(formattedWarnings))
-          .isNotEmpty) {
-        Expect.fail("Previously got error messages $prevFormattedWarnings, "
-            "now had ${formattedWarnings}.");
+
+      if (incrementalSerializationBytes != null) {
+        checkIsEqual(
+            incrementalSerializationBytes, incrementalSerializationBytes2);
       }
     }
 
@@ -623,6 +660,191 @@
       String expression = world["expressionCompilation"]["expression"];
       await compiler.compileExpression(expression, {}, [], "debugExpr", uri);
     }
+
+    if (!noFullComponent && incrementalSerialization == true) {
+      // Do compile from scratch and compare.
+      clearPrevErrorsEtc();
+      TestIncrementalCompiler compilerFromScratch;
+
+      IncrementalSerializer incrementalSerializer2;
+      if (incrementalSerialization == true) {
+        incrementalSerializer2 = new IncrementalSerializer();
+      }
+
+      if (world["fromComponent"] == true || modulesToUse != null) {
+        compilerFromScratch = new TestIncrementalCompiler.fromComponent(
+            options, entries.first, sdk, outlineOnly, incrementalSerializer2);
+      } else {
+        compilerFromScratch = new TestIncrementalCompiler(
+            options, entries.first, null, outlineOnly, incrementalSerializer2);
+      }
+
+      if (modulesToUse != null) {
+        compilerFromScratch.setModulesToLoadOnNextComputeDelta(modulesToUse);
+        compilerFromScratch.invalidateAllSources();
+        compilerFromScratch.trackNeededDillLibraries = true;
+      }
+
+      Stopwatch stopwatch = new Stopwatch()..start();
+      Component component3 = await compilerFromScratch.computeDelta(
+          entryPoints: entries,
+          simulateTransformer: world["simulateTransformer"]);
+      performErrorAndWarningCheck(
+          world, gotError, formattedErrors, gotWarning, formattedWarnings);
+      util.throwOnEmptyMixinBodies(component3);
+      util.throwOnInsufficientUriToSource(component3);
+      print("Compile took ${stopwatch.elapsedMilliseconds} ms");
+
+      util.postProcess(component3);
+      print("*****\n\ncomponent3:\n"
+          "${componentToStringSdkFiltered(component3)}\n\n\n");
+      checkErrorsAndWarnings(prevFormattedErrors, formattedErrors,
+          prevFormattedWarnings, formattedWarnings);
+
+      List<int> incrementalSerializationBytes3 = checkIncrementalSerialization(
+          incrementalSerialization, component3, incrementalSerializer2, world);
+
+      if ((incrementalSerializationBytes == null &&
+              incrementalSerializationBytes3 != null) ||
+          (incrementalSerializationBytes != null &&
+              incrementalSerializationBytes3 == null)) {
+        throw "Incremental serialization gave results in one instance, "
+            "but not another.";
+      }
+
+      if (incrementalSerializationBytes != null) {
+        if (world["brandNewIncrementalSerializationAllowDifferent"] == true) {
+          // Don't check for equality when we allow it to be different
+          // (e.g. when the old one contains more, and the new one doesn't).
+        } else {
+          checkIsEqual(
+              incrementalSerializationBytes, incrementalSerializationBytes3);
+        }
+        newestWholeComponentData = incrementalSerializationBytes;
+      }
+    }
+  }
+}
+
+void checkErrorsAndWarnings(
+    Set<String> prevFormattedErrors,
+    Set<String> formattedErrors,
+    Set<String> prevFormattedWarnings,
+    Set<String> formattedWarnings) {
+  if (prevFormattedErrors.length != formattedErrors.length) {
+    Expect.fail("Previously had ${prevFormattedErrors.length} errors, "
+        "now had ${formattedErrors.length}.\n\n"
+        "Before:\n"
+        "${prevFormattedErrors.join("\n")}"
+        "\n\n"
+        "Now:\n"
+        "${formattedErrors.join("\n")}");
+  }
+  if ((prevFormattedErrors.toSet()..removeAll(formattedErrors)).isNotEmpty) {
+    Expect.fail("Previously got error messages $prevFormattedErrors, "
+        "now had ${formattedErrors}.");
+  }
+  if (prevFormattedWarnings.length != formattedWarnings.length) {
+    Expect.fail("Previously had ${prevFormattedWarnings.length} errors, "
+        "now had ${formattedWarnings.length}.");
+  }
+  if ((prevFormattedWarnings.toSet()..removeAll(formattedWarnings))
+      .isNotEmpty) {
+    Expect.fail("Previously got error messages $prevFormattedWarnings, "
+        "now had ${formattedWarnings}.");
+  }
+}
+
+List<int> checkIncrementalSerialization(
+    bool incrementalSerialization,
+    Component component,
+    IncrementalSerializer incrementalSerializer,
+    YamlMap world) {
+  if (incrementalSerialization == true) {
+    Component c = new Component(nameRoot: component.root);
+    c.libraries.addAll(component.libraries);
+    c.uriToSource.addAll(component.uriToSource);
+    Map<String, Set<String>> originalContent = buildMapOfContent(c);
+    ByteSink sink = new ByteSink();
+    int librariesBefore = c.libraries.length;
+    incrementalSerializer.writePackagesToSinkAndTrimComponent(c, sink);
+    int librariesAfter = c.libraries.length;
+    if (librariesAfter > librariesBefore) {
+      throw "Incremental serialization added libraries!";
+    }
+    if (librariesBefore == librariesAfter &&
+        world["incrementalSerializationDoesWork"] == true) {
+      throw "Incremental serialization didn't remove any libraries!";
+    }
+    if (librariesAfter < librariesBefore && sink.builder.isEmpty) {
+      throw "Incremental serialization din't output any bytes, "
+          "but did remove libraries";
+    } else if (librariesAfter == librariesBefore && !sink.builder.isEmpty) {
+      throw "Incremental serialization did output bytes, "
+          "but didn't remove libraries";
+    }
+    if (librariesAfter < librariesBefore) {
+      // If we actually did incremenally serialize anything, check the output!
+      // If we actually did incremenally serialize anything, check the output!
+      BinaryPrinter printer = new BinaryPrinter(sink);
+      printer.writeComponentFile(c);
+      List<int> bytes = sink.builder.takeBytes();
+
+      // Load the bytes back in.
+      Component loadedComponent = new Component();
+      new BinaryBuilder(bytes, filename: null).readComponent(loadedComponent);
+
+      // Check that it doesn't contain anything we said it shouldn't.
+      if (world["serializationShouldNotInclude"] is List) {
+        List serializationShouldNotInclude =
+            world["serializationShouldNotInclude"];
+        Set<Uri> includedImportUris =
+            loadedComponent.libraries.map((l) => l.importUri).toSet();
+        for (String uriString in serializationShouldNotInclude) {
+          Uri uri = Uri.parse(uriString);
+          if (includedImportUris.contains(uri)) {
+            throw "Incremental serialization shouldn't include "
+                "$uriString but did.";
+          }
+        }
+      }
+
+      // Check that it contains at least what we want.
+      Map<String, Set<String>> afterContent =
+          buildMapOfContent(loadedComponent);
+      // Remove any keys in afterContent not in the original as the written
+      // one is allowed to contain *more*.
+      Set<String> newKeys = afterContent.keys.toSet()
+        ..removeAll(originalContent.keys);
+      for (String key in newKeys) {
+        afterContent.remove(key);
+      }
+      checkExpectedContentData(afterContent, originalContent);
+
+      // Check that the result is self-contained.
+      checkSelfContained(loadedComponent);
+
+      return bytes;
+    }
+  }
+  return null;
+}
+
+void checkSelfContained(Component component) {
+  Set<Library> got = new Set<Library>.from(component.libraries);
+  for (Library lib in component.libraries) {
+    for (LibraryDependency dependency in lib.dependencies) {
+      if (dependency.importedLibraryReference.node == null ||
+          !got.contains(dependency.targetLibrary)) {
+        if (dependency.importedLibraryReference.canonicalName
+            .toString()
+            .startsWith("root::dart:")) {
+          continue;
+        }
+        throw "Component didn't contain ${dependency.importedLibraryReference} "
+            "and it should have.";
+      }
+    }
   }
 }
 
@@ -635,6 +857,7 @@
   while (workList.isNotEmpty) {
     Library library = workList.removeLast();
     for (LibraryDependency dependency in library.dependencies) {
+      if (dependency.targetLibrary.importUri.scheme == "dart") continue;
       if (libraries.add(dependency.targetLibrary)) {
         workList.add(dependency.targetLibrary);
         allLibraries.add(dependency.targetLibrary);
@@ -645,41 +868,49 @@
 
 void checkExpectedContent(YamlMap world, Component component) {
   if (world["expectedContent"] != null) {
-    Map<String, Set<String>> actualContent = new Map<String, Set<String>>();
-    for (Library lib in component.libraries) {
-      Set<String> libContent =
-          actualContent[lib.importUri.toString()] = new Set<String>();
-      for (Class c in lib.classes) {
-        libContent.add("Class ${c.name}");
-      }
-      for (Procedure p in lib.procedures) {
-        libContent.add("Procedure ${p.name}");
-      }
-      for (Field f in lib.fields) {
-        libContent.add("Field ${f.name}");
-      }
-    }
-
+    Map<String, Set<String>> actualContent = buildMapOfContent(component);
     Map expectedContent = world["expectedContent"];
+    checkExpectedContentData(actualContent, expectedContent);
+  }
+}
 
-    doThrow() {
-      throw "Expected and actual content not the same.\n"
-          "Expected $expectedContent.\n"
-          "Got $actualContent";
+void checkExpectedContentData(
+    Map<String, Set<String>> actualContent, Map expectedContent) {
+  doThrow() {
+    throw "Expected and actual content not the same.\n"
+        "Expected $expectedContent.\n"
+        "Got $actualContent";
+  }
+
+  if (actualContent.length != expectedContent.length) doThrow();
+  Set<String> missingKeys = actualContent.keys.toSet()
+    ..removeAll(expectedContent.keys);
+  if (missingKeys.isNotEmpty) doThrow();
+  for (String key in expectedContent.keys) {
+    Set<String> expected = new Set<String>.from(expectedContent[key]);
+    Set<String> actual = actualContent[key].toSet();
+    if (expected.length != actual.length) doThrow();
+    actual.removeAll(expected);
+    if (actual.isNotEmpty) doThrow();
+  }
+}
+
+Map<String, Set<String>> buildMapOfContent(Component component) {
+  Map<String, Set<String>> actualContent = new Map<String, Set<String>>();
+  for (Library lib in component.libraries) {
+    Set<String> libContent =
+        actualContent[lib.importUri.toString()] = new Set<String>();
+    for (Class c in lib.classes) {
+      libContent.add("Class ${c.name}");
     }
-
-    if (actualContent.length != expectedContent.length) doThrow();
-    Set<String> missingKeys = actualContent.keys.toSet()
-      ..removeAll(expectedContent.keys);
-    if (missingKeys.isNotEmpty) doThrow();
-    for (String key in expectedContent.keys) {
-      Set<String> expected = new Set<String>.from(expectedContent[key]);
-      Set<String> actual = actualContent[key].toSet();
-      if (expected.length != actual.length) doThrow();
-      actual.removeAll(expected);
-      if (actual.isNotEmpty) doThrow();
+    for (Procedure p in lib.procedures) {
+      libContent.add("Procedure ${p.name}");
+    }
+    for (Field f in lib.fields) {
+      libContent.add("Field ${f.name}");
     }
   }
+  return actualContent;
 }
 
 void checkNeededDillLibraries(
@@ -967,20 +1198,25 @@
   }
 
   TestIncrementalCompiler(CompilerOptions options, this.entryPoint,
-      [Uri initializeFrom, bool outlineOnly])
+      [Uri initializeFrom,
+      bool outlineOnly,
+      IncrementalSerializer incrementalSerializer])
       : super(
             new CompilerContext(
                 new ProcessedOptions(options: options, inputs: [entryPoint])),
             initializeFrom,
-            outlineOnly);
+            outlineOnly,
+            incrementalSerializer);
 
   TestIncrementalCompiler.fromComponent(CompilerOptions options,
-      this.entryPoint, Component componentToInitializeFrom, [bool outlineOnly])
+      this.entryPoint, Component componentToInitializeFrom,
+      [bool outlineOnly, IncrementalSerializer incrementalSerializer])
       : super.fromComponent(
             new CompilerContext(
                 new ProcessedOptions(options: options, inputs: [entryPoint])),
             componentToInitializeFrom,
-            outlineOnly);
+            outlineOnly,
+            incrementalSerializer);
 
   @override
   void recordInvalidatedImportUrisForTesting(List<Uri> uris) {
diff --git a/pkg/front_end/test/lint_test.status b/pkg/front_end/test/lint_test.status
index 7f83b59..fb582ff 100644
--- a/pkg/front_end/test/lint_test.status
+++ b/pkg/front_end/test/lint_test.status
@@ -4,7 +4,6 @@
 
 src/api_unstable/bazel_worker/ImportsTwice: Fail
 src/fasta/builder/class_builder/ImportsTwice: Fail
-src/fasta/builder/field_builder/ImportsTwice: Fail
 src/fasta/incremental_compiler/ImportsTwice: Fail
 src/fasta/kernel/body_builder/ImportsTwice: Fail
 src/fasta/kernel/expression_generator_helper/ImportsTwice: Fail
@@ -21,7 +20,7 @@
 src/api_prototype/compiler_options/Exports: Fail
 src/api_prototype/constant_evaluator/Exports: Fail
 src/api_prototype/front_end/Exports: Fail
-src/fasta/builder/builder/Exports: Fail
+src/api_prototype/incremental_kernel_generator/Exports: Fail
 src/fasta/kernel/constant_evaluator/ExplicitType: Pass
 src/fasta/kernel/kernel_api/Exports: Fail
 src/fasta/kernel/kernel_ast_api/Exports: Fail
diff --git a/pkg/front_end/test/parser_test.dart b/pkg/front_end/test/parser_test.dart
index 10afc18..420d9fd 100644
--- a/pkg/front_end/test/parser_test.dart
+++ b/pkg/front_end/test/parser_test.dart
@@ -52,7 +52,8 @@
 
 Future<Context> createContext(
     Chain suite, Map<String, String> environment) async {
-  return new Context(environment["updateExpectations"] == "true");
+  return new Context(environment["updateExpectations"] == "true",
+      environment["trace"] == "true");
 }
 
 ScannerConfiguration scannerConfiguration = new ScannerConfiguration(
@@ -61,9 +62,10 @@
     enableNonNullable: true);
 
 class Context extends ChainContext with MatchContext {
-  final updateExpectations;
+  final bool updateExpectations;
+  final bool addTrace;
 
-  Context(this.updateExpectations);
+  Context(this.updateExpectations, this.addTrace);
 
   final List<Step> steps = const <Step>[
     const ListenerStep(),
@@ -95,7 +97,8 @@
       return crash(description, StackTrace.current);
     }
 
-    ParserTestListener parserTestListener = new ParserTestListener();
+    ParserTestListener parserTestListener =
+        new ParserTestListener(context.addTrace);
     Parser parser = new Parser(parserTestListener);
     parser.parseUnit(firstToken);
 
@@ -125,8 +128,9 @@
       return crash(description, StackTrace.current);
     }
 
-    ParserTestListener2 parserTestListener = new ParserTestListener2();
-    TestParser parser = new TestParser(parserTestListener);
+    ParserTestListener2 parserTestListener =
+        new ParserTestListener2(context.addTrace);
+    TestParser parser = new TestParser(parserTestListener, context.addTrace);
     parserTestListener.parser = parser;
     parser.sb = parserTestListener.sb;
     parser.parseUnit(firstToken);
@@ -139,7 +143,12 @@
 class ParserTestListener2 extends ParserTestListener {
   TestParser parser;
 
+  ParserTestListener2(bool trace) : super(trace);
+
   void doPrint(String s) {
-    sb.writeln(("  " * parser.indent) + "listener: " + s);
+    int prevIndent = super.indent;
+    super.indent = parser.indent;
+    super.doPrint("listener: " + s);
+    super.indent = prevIndent;
   }
 }
diff --git a/pkg/front_end/test/parser_test_listener.dart b/pkg/front_end/test/parser_test_listener.dart
index 8bd1ead..e3e83de 100644
--- a/pkg/front_end/test/parser_test_listener.dart
+++ b/pkg/front_end/test/parser_test_listener.dart
@@ -16,10 +16,27 @@
 
 class ParserTestListener implements Listener {
   int indent = 0;
-  StringBuffer sb = new StringBuffer();
+  final StringBuffer sb = new StringBuffer();
+  final bool trace;
+
+  ParserTestListener(this.trace);
+
+  String createTrace() {
+    List<String> traceLines = StackTrace.current.toString().split("\n");
+    for (int i = 0; i < traceLines.length; i++) {
+      // Find first one that's not any of the blacklisted ones.
+      String line = traceLines[i];
+      if (line.contains("parser_test_listener.dart:") ||
+          line.contains("parser_test.dart:")) continue;
+      return line.substring(line.indexOf("(") + 1, line.lastIndexOf(")"));
+    }
+    return "N/A";
+  }
 
   void doPrint(String s) {
-    sb.writeln(("  " * indent) + s);
+    String traceString = "";
+    if (trace) traceString = " (${createTrace()})";
+    sb.writeln(("  " * indent) + s + traceString);
   }
 
   Uri get uri => null;
@@ -1224,10 +1241,6 @@
     doPrint('endTypeVariables(' '$beginToken, ' '$endToken)');
   }
 
-  void handleVarianceModifier(Token variance) {
-    doPrint('handleVarianceModifier(' '$variance)');
-  }
-
   void reportVarianceModifierNotEnabled(Token variance) {
     doPrint('reportVarianceModifierNotEnabled(' '$variance)');
   }
diff --git a/pkg/front_end/test/parser_test_listener_creator.dart b/pkg/front_end/test/parser_test_listener_creator.dart
index 35851e7..5afed41 100644
--- a/pkg/front_end/test/parser_test_listener_creator.dart
+++ b/pkg/front_end/test/parser_test_listener_creator.dart
@@ -32,7 +32,7 @@
   Utf8BytesScanner scanner = new Utf8BytesScanner(bytes, includeComments: true);
   Token firstToken = scanner.tokenize();
 
-  out.write("""
+  out.write(r"""
 // 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.
@@ -51,10 +51,27 @@
 
 class ParserTestListener implements Listener {
   int indent = 0;
-  StringBuffer sb = new StringBuffer();
+  final StringBuffer sb = new StringBuffer();
+  final bool trace;
+
+  ParserTestListener(this.trace);
+
+  String createTrace() {
+    List<String> traceLines = StackTrace.current.toString().split("\n");
+    for (int i = 0; i < traceLines.length; i++) {
+      // Find first one that's not any of the blacklisted ones.
+      String line = traceLines[i];
+      if (line.contains("parser_test_listener.dart:") ||
+          line.contains("parser_test.dart:")) continue;
+      return line.substring(line.indexOf("(") + 1, line.lastIndexOf(")"));
+    }
+    return "N/A";
+  }
 
   void doPrint(String s) {
-    sb.writeln(("  " * indent) + s);
+    String traceString = "";
+    if (trace) traceString = " (${createTrace()})";
+    sb.writeln(("  " * indent) + s + traceString);
   }
 """);
 
diff --git a/pkg/front_end/test/parser_test_parser.dart b/pkg/front_end/test/parser_test_parser.dart
index 6d87b69..f5b5aae 100644
--- a/pkg/front_end/test/parser_test_parser.dart
+++ b/pkg/front_end/test/parser_test_parser.dart
@@ -19,13 +19,30 @@
 // THIS FILE IS AUTO GENERATED BY 'test/parser_test_parser_creator.dart'
 
 class TestParser extends Parser {
-  TestParser(Listener listener) : super(listener);
-
   int indent = 0;
   StringBuffer sb = new StringBuffer();
+  final bool trace;
+
+  TestParser(Listener listener, this.trace) : super(listener);
+
+  String createTrace() {
+    List<String> traceLines = StackTrace.current.toString().split("\n");
+    for (int i = 0; i < traceLines.length; i++) {
+      // Find first one that's not any of the blacklisted ones.
+      String line = traceLines[i];
+      if (line.contains("parser_test_listener.dart:") ||
+          line.contains("parser_test.dart:") ||
+          line.contains("parser_test_parser.dart:") ||
+          line == "<asynchronous suspension>") continue;
+      return line.substring(line.indexOf("(") + 1, line.lastIndexOf(")"));
+    }
+    return "N/A";
+  }
 
   void doPrint(String s) {
-    sb.writeln(("  " * indent) + s);
+    String traceString = "";
+    if (trace) traceString = " (${createTrace()})";
+    sb.writeln(("  " * indent) + s + traceString);
   }
 
   Uri get uri {
diff --git a/pkg/front_end/test/parser_test_parser_creator.dart b/pkg/front_end/test/parser_test_parser_creator.dart
index 2079d47..f4e4ebe 100644
--- a/pkg/front_end/test/parser_test_parser_creator.dart
+++ b/pkg/front_end/test/parser_test_parser_creator.dart
@@ -32,7 +32,7 @@
   Utf8BytesScanner scanner = new Utf8BytesScanner(bytes, includeComments: true);
   Token firstToken = scanner.tokenize();
 
-  out.write("""
+  out.write(r"""
 // 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.
@@ -54,13 +54,30 @@
 // THIS FILE IS AUTO GENERATED BY 'test/parser_test_parser_creator.dart'
 
 class TestParser extends Parser {
-  TestParser(Listener listener) : super(listener);
-
   int indent = 0;
   StringBuffer sb = new StringBuffer();
+  final bool trace;
+
+  TestParser(Listener listener, this.trace) : super(listener);
+
+  String createTrace() {
+    List<String> traceLines = StackTrace.current.toString().split("\n");
+    for (int i = 0; i < traceLines.length; i++) {
+      // Find first one that's not any of the blacklisted ones.
+      String line = traceLines[i];
+      if (line.contains("parser_test_listener.dart:") ||
+          line.contains("parser_test.dart:") ||
+          line.contains("parser_test_parser.dart:") ||
+          line == "<asynchronous suspension>") continue;
+      return line.substring(line.indexOf("(") + 1, line.lastIndexOf(")"));
+    }
+    return "N/A";
+  }
 
   void doPrint(String s) {
-    sb.writeln(("  " * indent) + s);
+    String traceString = "";
+    if (trace) traceString = " (${createTrace()})";
+    sb.writeln(("  " * indent) + s + traceString);
   }
 """);
 
diff --git a/pkg/front_end/test/patching/data/const_constructors/libraries.json b/pkg/front_end/test/patching/data/const_constructors/libraries.json
new file mode 100644
index 0000000..a697508
--- /dev/null
+++ b/pkg/front_end/test/patching/data/const_constructors/libraries.json
@@ -0,0 +1,12 @@
+{
+  "none": {
+    "libraries": {
+      "test": {
+        "patches": [
+          "patch.dart"
+        ],
+        "uri": "origin.dart"
+      }
+    }
+  }
+}
diff --git a/pkg/front_end/test/patching/data/const_constructors/main.dart b/pkg/front_end/test/patching/data/const_constructors/main.dart
new file mode 100644
index 0000000..b26f719
--- /dev/null
+++ b/pkg/front_end/test/patching/data/const_constructors/main.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.
+
+// ignore: uri_does_not_exist
+import 'dart:test';
+
+main() {
+  PatchedClass(field: 10);
+}
diff --git a/pkg/front_end/test/patching/data/const_constructors/origin.dart b/pkg/front_end/test/patching/data/const_constructors/origin.dart
new file mode 100644
index 0000000..e958a05
--- /dev/null
+++ b/pkg/front_end/test/patching/data/const_constructors/origin.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.
+
+/*class: PatchedClass:
+ kernel-members=[
+   PatchedClass.,
+   _field
+ ]
+*/
+class PatchedClass {
+  external const PatchedClass({int field});
+}
diff --git a/pkg/front_end/test/patching/data/const_constructors/patch.dart b/pkg/front_end/test/patching/data/const_constructors/patch.dart
new file mode 100644
index 0000000..4107bb0
--- /dev/null
+++ b/pkg/front_end/test/patching/data/const_constructors/patch.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.
+
+// ignore: import_internal_library
+import 'dart:_internal';
+
+@patch
+class PatchedClass {
+  final int _field;
+
+  /*member: PatchedClass.:
+    initializers=[FieldInitializer(_field),SuperInitializer],
+  */
+  @patch
+  const PatchedClass({int field}) : _field = field;
+}
diff --git a/pkg/front_end/test/patching/patching_test.dart b/pkg/front_end/test/patching/patching_test.dart
new file mode 100644
index 0000000..d8759ea
--- /dev/null
+++ b/pkg/front_end/test/patching/patching_test.dart
@@ -0,0 +1,106 @@
+// 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 Directory, Platform;
+
+import 'package:front_end/src/fasta/builder/builder.dart';
+import 'package:front_end/src/fasta/builder/class_builder.dart';
+
+import 'package:front_end/src/testing/id.dart' show ActualData, Id;
+import 'package:front_end/src/testing/features.dart';
+import 'package:front_end/src/testing/id_testing.dart'
+    show DataInterpreter, runTests;
+import 'package:front_end/src/testing/id_testing.dart';
+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';
+
+main(List<String> args) async {
+  Directory dataDir = new Directory.fromUri(Platform.script.resolve('data'));
+  await runTests(dataDir,
+      args: args,
+      supportedMarkers: sharedMarkers,
+      createUriForFileName: createUriForFileName,
+      onFailure: onFailure,
+      runTest: runTestFor(const PatchingDataComputer(), [
+        new TestConfig(cfeMarker, 'cfe with libraries specification',
+            librariesSpecificationUri: createUriForFileName('libraries.json'))
+      ]));
+}
+
+class PatchingDataComputer extends DataComputer<Features> {
+  const PatchingDataComputer();
+
+  @override
+  void computeMemberData(InternalCompilerResult compilerResult, Member member,
+      Map<Id, ActualData<Features>> actualMap,
+      {bool verbose}) {
+    member.accept(new PatchingDataExtractor(compilerResult, actualMap));
+  }
+
+  @override
+  void computeClassData(InternalCompilerResult compilerResult, Class cls,
+      Map<Id, ActualData<Features>> actualMap,
+      {bool verbose}) {
+    new PatchingDataExtractor(compilerResult, actualMap).computeForClass(cls);
+  }
+
+  void computeLibraryData(InternalCompilerResult compilerResult,
+      Library library, Map<Id, ActualData<Features>> actualMap,
+      {bool verbose}) {
+    new PatchingDataExtractor(compilerResult, actualMap)
+        .computeForLibrary(library);
+  }
+
+  @override
+  DataInterpreter<Features> get dataValidator =>
+      const FeaturesDataInterpreter();
+}
+
+class Tags {
+  static const String scope = 'scope';
+  static const String kernelMembers = 'kernel-members';
+  static const String initializers = 'initializers';
+}
+
+class PatchingDataExtractor extends CfeDataExtractor<Features> {
+  PatchingDataExtractor(InternalCompilerResult compilerResult,
+      Map<Id, ActualData<Features>> actualMap)
+      : super(compilerResult, actualMap);
+
+  @override
+  Features computeClassValue(Id id, Class cls) {
+    ClassBuilder clsBuilder = lookupClassBuilder(compilerResult, cls);
+
+    Features features = new Features();
+    clsBuilder.scope.forEach((String name, Builder builder) {
+      features.addElement(Tags.scope, name);
+    });
+
+    for (Member m in clsBuilder.actualCls.members) {
+      String name = m.name.name;
+      if (m is Constructor) {
+        name = '${m.enclosingClass.name}.${name}';
+      }
+      features.addElement(Tags.kernelMembers, name);
+    }
+
+    return features;
+  }
+
+  @override
+  Features computeMemberValue(Id id, Member member) {
+    Features features = new Features();
+    if (member is Constructor) {
+      for (Initializer initializer in member.initializers) {
+        String desc = initializer.runtimeType.toString();
+        if (initializer is FieldInitializer) {
+          desc = 'FieldInitializer(${getMemberName(initializer.field)})';
+        }
+        features.addElement(Tags.initializers, desc);
+      }
+    }
+    return features;
+  }
+}
diff --git a/pkg/front_end/test/severity_index_test.dart b/pkg/front_end/test/severity_index_test.dart
index 3070f73..fd7964b 100644
--- a/pkg/front_end/test/severity_index_test.dart
+++ b/pkg/front_end/test/severity_index_test.dart
@@ -9,13 +9,13 @@
 main() {
   expect(Severity.context.index, 0);
   expect(Severity.error.index, 1);
-  expect(Severity.internalProblem.index, 4);
-  expect(Severity.warning.index, 5);
+  expect(Severity.internalProblem.index, 3);
+  expect(Severity.warning.index, 4);
 
   expect(Severity.values[0], Severity.context);
   expect(Severity.values[1], Severity.error);
-  expect(Severity.values[4], Severity.internalProblem);
-  expect(Severity.values[5], Severity.warning);
+  expect(Severity.values[3], Severity.internalProblem);
+  expect(Severity.values[4], Severity.warning);
 }
 
 void expect(Object actual, Object expect) {
diff --git a/pkg/front_end/test/spell_checking_list_blacklist.txt b/pkg/front_end/test/spell_checking_list_blacklist.txt
index 9649873..f127418 100644
--- a/pkg/front_end/test/spell_checking_list_blacklist.txt
+++ b/pkg/front_end/test/spell_checking_list_blacklist.txt
@@ -6,7 +6,6 @@
 # Comments can also be inline like 'correct # this is ok'.
 # Note that at least one space before the hash is required.
 
-
 alread
 chnage
 clonable
@@ -63,6 +62,7 @@
 proram
 recomile
 resently
+reuslt
 satifying
 seach
 singluar
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index aa8e429..8b4cd40 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -211,6 +211,7 @@
 demands
 demangle
 demangled
+dep
 deps
 dereferenced
 dereferencing
@@ -446,6 +447,7 @@
 juxtaposition
 juxtapositions
 k
+k’s
 kallentu
 kernel's
 kernel2kernel
@@ -453,7 +455,6 @@
 kmillikin
 kustermann
 kv
-k’s
 l
 lacks
 lang
@@ -631,13 +632,13 @@
 quick
 quoted
 r
-r'$creation
 r'\f
 r'\r
 r'\s
 r'\t
 r'\u
 r'\v
+r'$creation
 radix
 raises
 ran
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 1ab6594..58d08a6 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -12,6 +12,7 @@
 able
 abort
 aborted
+aborting
 aborts
 about
 above
@@ -41,6 +42,7 @@
 accumulate
 accurate
 achieve
+act
 acting
 action
 active
@@ -183,6 +185,7 @@
 assignments
 associate
 associated
+associates
 associating
 associative
 assume
@@ -255,6 +258,7 @@
 beyond
 big
 bigint
+bilateral
 binaries
 binary
 bind
@@ -290,6 +294,7 @@
 bracketed
 brackets
 branch
+branched
 branches
 break
 breaking
@@ -332,7 +337,9 @@
 can
 can't
 cancel
+cancellation
 cancelled
+cancels
 candidate
 candidates
 cannot
@@ -394,6 +401,7 @@
 chunk
 circularities
 circularity
+circumstance
 circumstances
 clashing
 class
@@ -479,6 +487,7 @@
 complete
 completed
 completely
+completeness
 completer
 completion
 complex
@@ -569,6 +578,7 @@
 continued
 continues
 continuing
+continuously
 contraposition
 contrast
 contravariance
@@ -668,6 +678,7 @@
 deep
 default
 defaults
+defeating
 defensive
 defer
 deferred
@@ -878,6 +889,7 @@
 encoding
 encounter
 encountered
+encountering
 encounters
 end
 ended
@@ -960,6 +972,8 @@
 exclusive
 executable
 executed
+executes
+executing
 execution
 exercise
 exist
@@ -1063,6 +1077,7 @@
 find
 finding
 finds
+fine
 finish
 finished
 finishes
@@ -1135,6 +1150,7 @@
 fun
 function
 functionality
+functionally
 functions
 further
 furthermore
@@ -1325,6 +1341,7 @@
 indirect
 indirectly
 induce
+induced
 infer
 inference
 inferrable
@@ -1398,6 +1415,7 @@
 intercept
 interceptors
 interest
+interesting
 interface
 interfaces
 interferes
@@ -1427,6 +1445,8 @@
 invalidate
 invalidated
 invalidates
+invalidating
+invalidation
 invariant
 invariantly
 invert
@@ -1492,7 +1512,6 @@
 lack
 lacking
 lands
-langauge
 language
 large
 larger
@@ -1669,6 +1688,7 @@
 message
 messages
 messaging
+met
 metadata
 method
 methods
@@ -1905,6 +1925,7 @@
 owned
 owner
 package
+packaged
 packages
 pad
 padded
@@ -1949,6 +1970,8 @@
 peek
 pending
 percent
+percolate
+perfect
 perform
 performance
 performed
@@ -1960,6 +1983,7 @@
 permissible
 permitted
 persistent
+pertaining
 phase
 phased
 phases
@@ -2043,6 +2067,7 @@
 present
 preserve
 preserved
+preserves
 preserving
 presumed
 pretend
@@ -2089,6 +2114,7 @@
 project's
 projects
 prologue
+promotable
 promote
 promoted
 promoter
@@ -2213,6 +2239,7 @@
 register
 registered
 registers
+registration
 registry
 regress
 regression
@@ -2495,6 +2522,7 @@
 slower
 slows
 small
+smaller
 smallest
 snapshot
 snapshots
@@ -2557,6 +2585,7 @@
 startup
 state
 statement
+statement's
 statements
 states
 static
@@ -2567,6 +2596,7 @@
 steps
 still
 stop
+stopping
 stops
 stopwatch
 store
@@ -2651,6 +2681,7 @@
 surrogate
 surrogates
 surrounding
+survive
 survives
 suspect
 swap
@@ -2730,6 +2761,7 @@
 they
 they're
 thin
+thing
 things
 think
 third
@@ -2738,6 +2770,7 @@
 though
 three
 threshold
+threw
 throttle
 through
 throughout
@@ -2840,6 +2873,7 @@
 unchanged
 unclaimed
 unclear
+undeclared
 undefined
 under
 underlying
@@ -2958,6 +2992,7 @@
 via
 view
 viewed
+views
 violate
 violates
 violation
@@ -2981,6 +3016,7 @@
 was
 wasn't
 way
+ways
 we
 we'd
 we'll
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index e017d56..3eaeba6 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -338,6 +338,7 @@
 superinterface
 supermixin
 supplement
+suspension
 templates
 thereof
 thing
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 8e74122..33e0785 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
@@ -6,6 +6,8 @@
 // case the supertype of the match is a FutureOr<X> or one of its alternatives
 // (either Future<X> or X).
 
+/*cfe.library: nnbd=false*/
+/*cfe:nnbd.library: nnbd=true*/
 import 'dart:async';
 
 // -----------------------------------------------------------------------------
@@ -49,7 +51,7 @@
 void func5() {
   void foo<S>(FutureOr<S> bar) {}
 
-  /*invoke: void*/ foo/*<int>*/(/*int*/ 42);
+  /*invoke: void*/ foo /*cfe|dart2js.<int>*/ /*cfe:nnbd.<int!>*/ (/*int*/ 42);
 }
 
 // -----------------------------------------------------------------------------
@@ -58,7 +60,7 @@
 void func6() {
   void foo<S>(S bar) {}
 
-  /*invoke: void*/ foo/*<int>*/(/*int*/ 42);
+  /*invoke: void*/ foo /*cfe|dart2js.<int>*/ /*cfe:nnbd.<int!>*/ (/*int*/ 42);
 }
 
 // -----------------------------------------------------------------------------
@@ -66,7 +68,7 @@
 void func7() {
   void foo<S>(FutureOr<FutureOr<S>> bar) {}
 
-  /*invoke: void*/ foo/*<int>*/(/*int*/ 42);
+  /*invoke: void*/ foo /*cfe|dart2js.<int>*/ /*cfe:nnbd.<int!>*/ (/*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 40e7d21..6c3c239 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
@@ -5,6 +5,8 @@
 // This test checks that the greatest lower bound between two types is
 // calculated correctly, in case one of them is a FutureOr.
 
+/*cfe.library: nnbd=false*/
+/*cfe:nnbd.library: nnbd=true*/
 import 'dart:async';
 
 class Foo {}
@@ -23,7 +25,10 @@
   S expr<S extends Foo>() => /*Null*/ null;
 
   // Type of the expression is GLB(FutureOr<T>, Foo) = T.
-  /*invoke: void*/ context(/*invoke: T*/ expr/*<T>*/());
+  /*invoke: void*/ context(
+      /*invoke: T*/ expr
+          /*cfe|dart2js.<T>*/
+          /*cfe:nnbd.<T!>*/ ());
 }
 
 // -----------------------------------------------------------------------------
@@ -34,7 +39,11 @@
   S expr<S extends Future<Foo>>() => /*Null*/ null;
 
   // Type of the expression is GLB(FutureOr<T>, Future<Foo>) = Future<T>.
-  /*invoke: void*/ context(/*invoke: Future<T>*/ expr/*<Future<T>>*/());
+  /*invoke: void*/ context(
+      /*cfe|dart2js.invoke: Future<T>*/
+      /*cfe:nnbd.invoke: Future<T!>*/ expr
+          /*cfe|dart2js.<Future<T>>*/
+          /*cfe:nnbd.<Future<T!>>*/ ());
 }
 
 // -----------------------------------------------------------------------------
@@ -45,7 +54,10 @@
   S expr<S extends FutureOr<Foo>>() => /*Null*/ null;
 
   // Type of the expression is GLB(T, FutureOr<Foo>) = T.
-  /*invoke: void*/ context(/*invoke: T*/ expr/*<T>*/());
+  /*invoke: void*/ context(
+      /*invoke: T*/ expr
+          /*cfe|dart2js.<T>*/
+          /*cfe:nnbd.<T!>*/ ());
 }
 
 // -----------------------------------------------------------------------------
@@ -56,7 +68,11 @@
   S expr<S extends FutureOr<Foo>>() => /*Null*/ null;
 
   // Type of the expression is GLB(Future<T>, FutureOr<Foo>) = Future<T>.
-  /*invoke: void*/ context(/*invoke: Future<T>*/ expr/*<Future<T>>*/());
+  /*invoke: void*/ context(
+      /*cfe|dart2js.invoke: Future<T>*/
+      /*cfe:nnbd.invoke: Future<T!>*/ expr
+          /*cfe|dart2js.<Future<T>>*/
+          /*cfe:nnbd.<Future<T!>!>*/ ());
 }
 
 // -----------------------------------------------------------------------------
@@ -70,7 +86,10 @@
   // Type of the expression is GLB(FutureOr<FutureOr<T>>, FutureOr<Future<Foo>>)
   // = FutureOr<Future<T>>.
   /*invoke: void*/ context(
-      /*invoke: FutureOr<Future<T>>*/ expr/*<FutureOr<Future<T>>>*/());
+      /*cfe|dart2js.invoke: FutureOr<Future<T>>*/
+      /*cfe:nnbd.invoke: FutureOr<Future<T!>>*/ expr
+          /*cfe|dart2js.<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 1c91bbe..c8fb05d 100644
--- a/pkg/front_end/test/static_types/data/list_literals.dart
+++ b/pkg/front_end/test/static_types/data/list_literals.dart
@@ -2,9 +2,17 @@
 // for 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.library: nnbd=false*/
+/*cfe:nnbd.library: nnbd=true*/
+
 main() {
   /*List<dynamic>*/ [];
-  /*List<int>*/ [/*int*/ 0];
+
+  /*cfe|dart2js.List<int>*/
+  /*cfe:nnbd.List<int!>*/
+  [/*int*/ 0];
+
   /*List<num>*/ [/*int*/ 0, /*double*/ 0.5];
+
   /*List<Object>*/ [/*int*/ 0, /*String*/ ''];
 }
diff --git a/pkg/front_end/test/static_types/data/literals.dart b/pkg/front_end/test/static_types/data/literals.dart
index 6077b43..52c32a1 100644
--- a/pkg/front_end/test/static_types/data/literals.dart
+++ b/pkg/front_end/test/static_types/data/literals.dart
@@ -2,6 +2,9 @@
 // for 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.library: nnbd=false*/
+/*cfe:nnbd.library: nnbd=true*/
+
 main() {
   /*Null*/ null;
   /*bool*/ true;
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 42cb934..ce2e5fb 100644
--- a/pkg/front_end/test/static_types/data/map_literals.dart
+++ b/pkg/front_end/test/static_types/data/map_literals.dart
@@ -2,35 +2,67 @@
 // for 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.library: nnbd=false*/
+/*cfe:nnbd.library: nnbd=true*/
+
 main() {
   // ignore: unused_local_variable
   var a0 = /*Map<dynamic,dynamic>*/ {};
+
   // ignore: unused_local_variable
-  var a1 = /*Map<int,double>*/ {/*int*/ 0: /*double*/ 0.5 };
+  var a1 =
+      /*cfe|dart2js.Map<int,double>*/
+      /*cfe:nnbd.Map<int!,double!>*/
+      {/*int*/ 0: /*double*/ 0.5 };
+
   // ignore: unused_local_variable
-  var a2 = /*Map<double,int>*/ {/*double*/ 0.5: /*int*/ 0 };
+  var a2 =
+      /*cfe|dart2js.Map<double,int>*/
+      /*cfe:nnbd.Map<double!,int!>*/
+      {/*double*/ 0.5: /*int*/ 0 };
+
   // ignore: unused_local_variable
-  var a3 = /*Map<int,num>*/ {/*int*/ 0: /*double*/ 0.5, /*int*/ 1: /*int*/ 2 };
+  var a3 =
+      /*cfe|dart2js.Map<int,num>*/
+      /*cfe:nnbd.Map<int!,num>*/
+      {
+    /*int*/ 0: /*double*/ 0.5,
+    /*int*/ 1: /*int*/ 2
+  };
+
   // ignore: unused_local_variable
-  var a4 = /*Map<num,double>*/ {
+  var a4 =
+      /*cfe|dart2js.Map<num,double>*/
+      /*cfe:nnbd.Map<num,double!>*/
+      {
     /*int*/ 0: /*double*/ 0.5,
     /*double*/ 0.5: /*double*/ 0.5
   };
+
   // ignore: unused_local_variable
   var a5 = /*Map<num,num>*/ {
     /*int*/ 0: /*double*/ 0.5,
     /*double*/ 0.5: /*int*/ 0
   };
+
   // ignore: unused_local_variable
-  var a6 = /*Map<int,Object>*/ {
+  var a6 =
+      /*cfe|dart2js.Map<int,Object>*/
+      /*cfe:nnbd.Map<int!,Object>*/
+      {
     /*int*/ 0: /*double*/ 0.5,
     /*int*/ 1: /*String*/ ''
   };
+
   // ignore: unused_local_variable
-  var a7 = /*Map<Object,double>*/ {
+  var a7 =
+      /*cfe|dart2js.Map<Object,double>*/
+      /*cfe:nnbd.Map<Object,double!>*/
+      {
     /*int*/ 0: /*double*/ 0.5,
     /*String*/ '': /*double*/ 0.5
   };
+
   // ignore: unused_local_variable
   var a8 = /*Map<Object,Object>*/ {
     /*int*/ 0: /*double*/ 0.5,
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 56ea80b..6f59a39 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
@@ -2,11 +2,17 @@
 // for 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.library: nnbd=false*/
+/*cfe:nnbd.library: nnbd=true*/
+
 class Class {}
 
 main() {
   var o;
-  // ignore: unused_local_variable
-  /*as: Class*/ for (Class c
+  /*cfe|dart2js.as: Class*/
+  /*cfe:nnbd.as: Class!*/
+  for (
+      // ignore: UNUSED_LOCAL_VARIABLE
+      Class c
       in /*as: Iterable<dynamic>*/ /*dynamic*/ o?. /*dynamic*/ iterable) {}
 }
diff --git a/pkg/front_end/test/static_types/data/opt_out.dart b/pkg/front_end/test/static_types/data/opt_out.dart
new file mode 100644
index 0000000..40057af
--- /dev/null
+++ b/pkg/front_end/test/static_types/data/opt_out.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.
+
+// @dart = 2.5
+
+/*cfe.library: nnbd=false*/
+/*cfe:nnbd.library: nnbd=false*/
+
+int topLevel;
+
+main() {
+  /*int*/ topLevel;
+}
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 a6b9d6e..83ff887 100644
--- a/pkg/front_end/test/static_types/data/prefix_postfix.dart
+++ b/pkg/front_end/test/static_types/data/prefix_postfix.dart
@@ -2,27 +2,79 @@
 // for 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.library: nnbd=false*/
+/*cfe:nnbd.library: nnbd=true*/
+
 num numTopLevel = /*int*/ 0;
 int intTopLevel = /*int*/ 0;
 dynamic dynamicTopLevel = /*int*/ 0;
 
 testTopLevel() {
-  /*update: num*/ /*num*/ numTopLevel /*invoke: num*/ /*int*/ ++;
-  /*update: num*/ /*num*/ numTopLevel /*invoke: num*/ /*int*/ --;
-  /*invoke: num*/ /*int*/ ++ /*update: num*/ /*num*/ numTopLevel;
-  /*invoke: num*/ /*int*/ -- /*update: num*/ /*num*/ numTopLevel;
+  /*update: num*/
+  /*cfe|dart2js.num*/
+  /*cfe:nnbd.num!*/
+  numTopLevel /*invoke: num*/ /*int*/ ++;
 
-  /*update: int*/ /*int*/ intTopLevel /*invoke: int*/ /*int*/ ++;
-  /*update: int*/ /*int*/ intTopLevel /*invoke: int*/ /*int*/ --;
-  /*invoke: int*/ /*int*/ ++ /*update: int*/ /*int*/ intTopLevel;
-  /*invoke: int*/ /*int*/ -- /*update: int*/ /*int*/ intTopLevel;
+  /*update: num*/
+  /*cfe|dart2js.num*/
+  /*cfe:nnbd.num!*/
+  numTopLevel /*invoke: num*/ /*int*/ --;
+
+  /*invoke: num*/ /*int*/ ++ /*update: num*/
+      /*cfe|dart2js.num*/
+      /*cfe:nnbd.num!*/
+      numTopLevel;
+
+  /*invoke: num*/ /*int*/ -- /*update: num*/
+      /*cfe|dart2js.num*/
+      /*cfe:nnbd.num!*/
+      numTopLevel;
+
+  /*cfe|dart2js.update: int*/
+  /*cfe:nnbd.update: int!*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  intTopLevel
+      /*cfe|dart2js.invoke: int*/
+      /*cfe:nnbd.invoke: int!*/
+      /*int*/ ++;
+
+  /*cfe|dart2js.update: int*/
+  /*cfe:nnbd.update: int!*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  intTopLevel
+      /*cfe|dart2js.invoke: int*/
+      /*cfe:nnbd.invoke: int!*/
+      /*int*/ --;
+
+  /*cfe|dart2js.invoke: int*/
+  /*cfe:nnbd.invoke: int!*/
+  /*int*/ ++
+      /*cfe|dart2js.update: int*/
+      /*cfe:nnbd.update: int!*/
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      intTopLevel;
+
+  /*cfe|dart2js.invoke: int*/
+  /*cfe:nnbd.invoke: int!*/
+  /*int*/ --
+      /*cfe|dart2js.update: int*/
+      /*cfe:nnbd.update: int!*/
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      intTopLevel;
 
   /*update: dynamic*/ /*dynamic*/ dynamicTopLevel
       /*invoke: dynamic*/ /*int*/ ++;
+
   /*update: dynamic*/ /*dynamic*/ dynamicTopLevel
       /*invoke: dynamic*/ /*int*/ --;
+
   /*invoke: dynamic*/ /*int*/ ++
       /*update: dynamic*/ /*dynamic*/ dynamicTopLevel;
+
   /*invoke: dynamic*/ /*int*/ --
       /*update: dynamic*/ /*dynamic*/ dynamicTopLevel;
 }
@@ -33,15 +85,61 @@
   dynamic dynamicInstance = /*int*/ 0;
 
   testInstance() {
-    /*update: num*/ /*num*/ numInstance /*invoke: num*/ /*int*/ ++;
-    /*update: num*/ /*num*/ numInstance /*invoke: num*/ /*int*/ --;
-    /*invoke: num*/ /*int*/ ++ /*update: num*/ /*num*/ numInstance;
-    /*invoke: num*/ /*int*/ -- /*update: num*/ /*num*/ numInstance;
+    /*update: num*/
+    /*cfe|dart2js.num*/
+    /*cfe:nnbd.num!*/
+    numInstance /*invoke: num*/ /*int*/ ++;
 
-    /*update: int*/ /*int*/ intInstance /*invoke: int*/ /*int*/ ++;
-    /*update: int*/ /*int*/ intInstance /*invoke: int*/ /*int*/ --;
-    /*invoke: int*/ /*int*/ ++ /*update: int*/ /*int*/ intInstance;
-    /*invoke: int*/ /*int*/ -- /*update: int*/ /*int*/ intInstance;
+    /*update: num*/
+    /*cfe|dart2js.num*/
+    /*cfe:nnbd.num!*/
+    numInstance /*invoke: num*/ /*int*/ --;
+
+    /*invoke: num*/ /*int*/ ++ /*update: num*/
+        /*cfe|dart2js.num*/
+        /*cfe:nnbd.num!*/
+        numInstance;
+
+    /*invoke: num*/ /*int*/ -- /*update: num*/
+        /*cfe|dart2js.num*/
+        /*cfe:nnbd.num!*/
+        numInstance;
+
+    /*cfe|dart2js.update: int*/
+    /*cfe:nnbd.update: int!*/
+    /*cfe|dart2js.int*/
+    /*cfe:nnbd.int!*/
+    intInstance
+        /*cfe|dart2js.invoke: int*/
+        /*cfe:nnbd.invoke: int!*/
+        /*int*/ ++;
+
+    /*cfe|dart2js.update: int*/
+    /*cfe:nnbd.update: int!*/
+    /*cfe|dart2js.int*/
+    /*cfe:nnbd.int!*/
+    intInstance
+        /*cfe|dart2js.invoke: int*/
+        /*cfe:nnbd.invoke: int!*/
+        /*int*/ --;
+
+    /*cfe|dart2js.invoke: int*/
+    /*cfe:nnbd.invoke: int!*/
+    /*int*/ ++
+        /*cfe|dart2js.update: int*/
+        /*cfe:nnbd.update: int!*/
+        /*cfe|dart2js.int*/
+        /*cfe:nnbd.int!*/
+        intInstance;
+
+    /*cfe|dart2js.invoke: int*/
+    /*cfe:nnbd.invoke: int!*/
+    /*int*/ --
+        /*cfe|dart2js.update: int*/
+        /*cfe:nnbd.update: int!*/
+        /*cfe|dart2js.int*/
+        /*cfe:nnbd.int!*/
+        intInstance;
 
     /*update: dynamic*/ /*dynamic*/ dynamicInstance
         /*invoke: dynamic*/ /*int*/ ++;
@@ -55,24 +153,100 @@
 }
 
 testInstanceOnClass(Class c) {
-  /*Class*/ c. /*update: num*/ /*num*/ numInstance /*invoke: num*/ /*int*/ ++;
-  /*Class*/ c. /*update: num*/ /*num*/ numInstance /*invoke: num*/ /*int*/ --;
-  /*invoke: num*/ /*int*/ ++ /*Class*/ c. /*update: num*/ /*num*/ numInstance;
-  /*invoke: num*/ /*int*/ -- /*Class*/ c. /*update: num*/ /*num*/ numInstance;
+  /*cfe|dart2js.Class*/
+  /*cfe:nnbd.Class!*/
+  c. /*update: num*/
+      /*cfe|dart2js.num*/
+      /*cfe:nnbd.num!*/
+      numInstance /*invoke: num*/ /*int*/ ++;
+  /*cfe|dart2js.Class*/
+  /*cfe:nnbd.Class!*/
+  c. /*update: num*/
+      /*cfe|dart2js.num*/
+      /*cfe:nnbd.num!*/
+      numInstance /*invoke: num*/ /*int*/ --;
+  /*invoke: num*/ /*int*/ ++
+      /*cfe|dart2js.Class*/
+      /*cfe:nnbd.Class!*/
+      c. /*update: num*/
+          /*cfe|dart2js.num*/
+          /*cfe:nnbd.num!*/
+          numInstance;
+  /*invoke: num*/ /*int*/ --
+      /*cfe|dart2js.Class*/
+      /*cfe:nnbd.Class!*/
+      c. /*update: num*/
+          /*cfe|dart2js.num*/
+          /*cfe:nnbd.num!*/
+          numInstance;
 
-  /*Class*/ c. /*update: int*/ /*int*/ intInstance /*invoke: int*/ /*int*/ ++;
-  /*Class*/ c. /*update: int*/ /*int*/ intInstance /*invoke: int*/ /*int*/ --;
-  /*invoke: int*/ /*int*/ ++ /*Class*/ c. /*update: int*/ /*int*/ intInstance;
-  /*invoke: int*/ /*int*/ -- /*Class*/ c. /*update: int*/ /*int*/ intInstance;
+  /*cfe|dart2js.Class*/
+  /*cfe:nnbd.Class!*/
+  c.
+          /*cfe|dart2js.update: int*/
+          /*cfe:nnbd.update: int!*/
+          /*cfe|dart2js.int*/
+          /*cfe:nnbd.int!*/
+          intInstance
+      /*cfe|dart2js.invoke: int*/
+      /*cfe:nnbd.invoke: int!*/
+      /*int*/ ++;
 
-  /*Class*/ c. /*update: dynamic*/ /*dynamic*/ dynamicInstance
+  /*cfe|dart2js.Class*/
+  /*cfe:nnbd.Class!*/
+  c.
+          /*cfe|dart2js.update: int*/
+          /*cfe:nnbd.update: int!*/
+          /*cfe|dart2js.int*/
+          /*cfe:nnbd.int!*/
+          intInstance
+      /*cfe|dart2js.invoke: int*/
+      /*cfe:nnbd.invoke: int!*/
+      /*int*/ --;
+
+  /*cfe|dart2js.invoke: int*/
+  /*cfe:nnbd.invoke: int!*/
+  /*int*/ ++
+      /*cfe|dart2js.Class*/
+      /*cfe:nnbd.Class!*/
+      c.
+          /*cfe|dart2js.update: int*/
+          /*cfe:nnbd.update: int!*/
+          /*cfe|dart2js.int*/
+          /*cfe:nnbd.int!*/
+          intInstance;
+
+  /*cfe|dart2js.invoke: int*/
+  /*cfe:nnbd.invoke: int!*/
+  /*int*/ --
+      /*cfe|dart2js.Class*/
+      /*cfe:nnbd.Class!*/
+      c.
+          /*cfe|dart2js.update: int*/
+          /*cfe:nnbd.update: int!*/
+          /*cfe|dart2js.int*/
+          /*cfe:nnbd.int!*/
+          intInstance;
+
+  /*cfe|dart2js.Class*/
+  /*cfe:nnbd.Class!*/
+  c. /*update: dynamic*/ /*dynamic*/ dynamicInstance
       /*invoke: dynamic*/ /*int*/ ++;
-  /*Class*/ c. /*update: dynamic*/ /*dynamic*/ dynamicInstance
+
+  /*cfe|dart2js.Class*/
+  /*cfe:nnbd.Class!*/
+  c. /*update: dynamic*/ /*dynamic*/ dynamicInstance
       /*invoke: dynamic*/ /*int*/ --;
-  /*invoke: dynamic*/ /*int*/ ++ /*Class*/ c
-      . /*update: dynamic*/ /*dynamic*/ dynamicInstance;
-  /*invoke: dynamic*/ /*int*/ -- /*Class*/ c
-      . /*update: dynamic*/ /*dynamic*/ dynamicInstance;
+
+  /*invoke: dynamic*/ /*int*/ ++
+      /*cfe|dart2js.Class*/
+      /*cfe:nnbd.Class!*/
+      c. /*update: dynamic*/ /*dynamic*/ dynamicInstance;
+
+  /*invoke: dynamic*/ /*int*/ --
+      /*cfe|dart2js.Class*/
+      /*cfe:nnbd.Class!*/
+      c. /*update: dynamic*/ /*dynamic*/ dynamicInstance;
 }
 
 testInstanceOnDynamic(dynamic c) {
@@ -114,18 +288,67 @@
   /// ignore: unused_local_variable
   dynamic dynamicLocal = /*int*/ 0;
 
-  /*update: num*/ /*num*/ numLocal /*invoke: num*/ /*int*/ ++;
-  /*update: num*/ /*num*/ numLocal /*invoke: num*/ /*int*/ --;
-  /*invoke: num*/ /*int*/ ++ /*update: num*/ /*num*/ numLocal;
-  /*invoke: num*/ /*int*/ -- /*update: num*/ /*num*/ numLocal;
+  /*update: num*/
+  /*cfe|dart2js.num*/
+  /*cfe:nnbd.num!*/
+  numLocal /*invoke: num*/ /*int*/ ++;
 
-  /*update: int*/ /*int*/ intLocal /*invoke: int*/ /*int*/ ++;
-  /*update: int*/ /*int*/ intLocal /*invoke: int*/ /*int*/ --;
-  /*invoke: int*/ /*int*/ ++ /*update: int*/ /*int*/ intLocal;
-  /*invoke: int*/ /*int*/ -- /*update: int*/ /*int*/ intLocal;
+  /*update: num*/
+  /*cfe|dart2js.num*/
+  /*cfe:nnbd.num!*/
+  numLocal /*invoke: num*/ /*int*/ --;
+
+  /*invoke: num*/ /*int*/ ++ /*update: num*/
+      /*cfe|dart2js.num*/
+      /*cfe:nnbd.num!*/
+      numLocal;
+
+  /*invoke: num*/ /*int*/ -- /*update: num*/
+      /*cfe|dart2js.num*/
+      /*cfe:nnbd.num!*/
+      numLocal;
+
+  /*cfe|dart2js.update: int*/
+  /*cfe:nnbd.update: int!*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  intLocal
+      /*cfe|dart2js.invoke: int*/
+      /*cfe:nnbd.invoke: int!*/
+      /*int*/ ++;
+
+  /*cfe|dart2js.update: int*/
+  /*cfe:nnbd.update: int!*/
+  /*cfe|dart2js.int*/
+  /*cfe:nnbd.int!*/
+  intLocal
+      /*cfe|dart2js.invoke: int*/
+      /*cfe:nnbd.invoke: int!*/
+      /*int*/ --;
+
+  /*cfe|dart2js.invoke: int*/
+  /*cfe:nnbd.invoke: int!*/
+  /*int*/ ++
+      /*cfe|dart2js.update: int*/
+      /*cfe:nnbd.update: int!*/
+      /*cfe|dart2js.int*/
+      /*cfe:nnbd.int!*/
+      intLocal;
+
+  /*cfe|dart2js.invoke: int*/
+  /*cfe:nnbd.invoke: int!*/
+  /*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*/ /*int*/ --;
+
   /*invoke: dynamic*/ /*int*/ ++ /*update: dynamic*/ /*dynamic*/ dynamicLocal;
+
   /*invoke: dynamic*/ /*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
new file mode 100644
index 0000000..9cc7227
--- /dev/null
+++ b/pkg/front_end/test/static_types/data/promoted_access.dart
@@ -0,0 +1,30 @@
+// 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.
+
+/*cfe.library: nnbd=false*/
+/*cfe:nnbd.library: nnbd=true*/
+
+class Class<T> {
+  method(T o) {
+    if (/*cfe|dart2js.T*/ /*cfe:nnbd.T%*/ o is Class) {
+      /*cfe|dart2js.T extends Class<dynamic>*/
+      /*cfe:nnbd.T! extends Class<dynamic>!*/
+      o. /*invoke: dynamic*/ method(/*Null*/ null);
+    }
+  }
+}
+
+method<T>(T o) {
+  if (/*cfe|dart2js.T*/ /*cfe:nnbd.T%*/ o is Class) {
+    /*cfe|dart2js.T extends Class<dynamic>*/
+    /*cfe:nnbd.T! extends Class<dynamic>!*/
+    o. /*invoke: dynamic*/ method(/*Null*/ null);
+  }
+}
+
+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);
+}
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 7c40277..e7efad8 100644
--- a/pkg/front_end/test/static_types/data/set_literals.dart
+++ b/pkg/front_end/test/static_types/data/set_literals.dart
@@ -2,13 +2,22 @@
 // for 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.library: nnbd=false*/
+/*cfe:nnbd.library: nnbd=true*/
+
 main() {
   // ignore: unused_local_variable
   var a0 = /*Map<dynamic,dynamic>*/ {};
+
   // ignore: unused_local_variable
-  var a1 = /*Set<int>*/ {/*int*/ 0};
+  var a1 =
+      /*cfe|dart2js.Set<int>*/
+      /*cfe:nnbd.Set<int!>*/
+      {/*int*/ 0};
+
   // ignore: unused_local_variable
   var a2 = /*Set<num>*/ {/*int*/ 0, /*double*/ 0.5};
+
   // ignore: unused_local_variable
   var a3 = /*Set<Object>*/ {/*int*/ 0, /*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 0014368..139b423 100644
--- a/pkg/front_end/test/static_types/static_type_test.dart
+++ b/pkg/front_end/test/static_types/static_type_test.dart
@@ -16,15 +16,26 @@
   Directory dataDir = new Directory.fromUri(Platform.script.resolve('data'));
   await runTests(dataDir,
       args: args,
-      supportedMarkers: sharedMarkers,
+      supportedMarkers: sharedMarkersWithNnbd,
       createUriForFileName: createUriForFileName,
       onFailure: onFailure,
-      runTest: runTestFor(const StaticTypeDataComputer(), [defaultCfeConfig]));
+      runTest: runTestFor(const StaticTypeDataComputer(),
+          [defaultCfeConfig, cfeNonNullableConfig]));
 }
 
 class StaticTypeDataComputer extends DataComputer<String> {
   const StaticTypeDataComputer();
 
+  /// Function that computes a data mapping for [library].
+  ///
+  /// Fills [actualMap] with the data.
+  void computeLibraryData(InternalCompilerResult compilerResult,
+      Library library, Map<Id, ActualData<String>> actualMap,
+      {bool verbose}) {
+    new StaticTypeDataExtractor(compilerResult, actualMap)
+        .computeForLibrary(library);
+  }
+
   @override
   void computeMemberData(InternalCompilerResult compilerResult, Member member,
       Map<Id, ActualData<String>> actualMap,
@@ -47,6 +58,11 @@
         super(compilerResult, actualMap);
 
   @override
+  String computeLibraryValue(Id id, Library node) {
+    return 'nnbd=${node.isNonNullableByDefault}';
+  }
+
+  @override
   String computeNodeValue(Id id, TreeNode node) {
     if (node is Expression) {
       DartType type = node.getStaticType(_environment);
diff --git a/pkg/front_end/test/token_test.dart b/pkg/front_end/test/token_test.dart
index cef530f..6ab5a00 100644
--- a/pkg/front_end/test/token_test.dart
+++ b/pkg/front_end/test/token_test.dart
@@ -95,6 +95,7 @@
       Keyword.IMPLEMENTS,
       Keyword.IMPORT,
       Keyword.INTERFACE,
+      Keyword.LATE,
       Keyword.LIBRARY,
       Keyword.MIXIN,
       Keyword.OPERATOR,
diff --git a/pkg/front_end/testcases/extensions/check_bounds.dart b/pkg/front_end/testcases/extensions/check_bounds.dart
index 60a157d..1772b28 100644
--- a/pkg/front_end/testcases/extensions/check_bounds.dart
+++ b/pkg/front_end/testcases/extensions/check_bounds.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.
 
+part 'check_bounds_lib.dart';
+
 class A {}
+
 class B extends A {}
 
 class Class<T extends A> {}
@@ -12,35 +15,87 @@
   genericMethod<S extends B>(S s) {}
 }
 
-main() {
-
-}
+main() {}
 
 test() {
   A a;
 
   Class<A> classA = new Class<A>();
-  classA.method();
-  Extension(classA).method();
-  Extension<A>(classA).method();
+  classA.method(); // Expect method not found.
+  Extension(classA).method(); // Expect bounds mismatch.
+  Extension<A>(classA).method(); // Expect bounds mismatch.
   Extension<B>(classA).method();
+  Extension(classA).genericMethod(a); // Expect bounds mismatch.
+  Extension(classA).genericMethod<A>(a); // Expect bounds mismatch.
+  Extension(classA).genericMethod<B>(a); // Expect bounds mismatch.
+  Extension<A>(classA).genericMethod(a); // Expect bounds mismatch.
+  Extension<A>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+  Extension<A>(classA).genericMethod<B>(a); // Expect bounds mismatch.
+  Extension<B>(classA).genericMethod(a); // Expect bounds mismatch.
+  Extension<B>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+  Extension<B>(classA).genericMethod<B>(a);
 
   Class<B> classB = new Class<B>();
   classB.method();
   Extension(classB).method();
-  Extension<A>(classB).method();
+  Extension<A>(classB).method(); // Expect bounds mismatch.
   Extension<B>(classB).method();
 
-  classB.genericMethod(a);
-  classB.genericMethod<A>(a);
+  classB.genericMethod(a); // Expect bounds mismatch.
+  classB.genericMethod<A>(a); // Expect bounds mismatch.
   classB.genericMethod<B>(a);
-  Extension(classB).genericMethod(a);
-  Extension(classB).genericMethod<A>(a);
+  Extension(classB).genericMethod(a); // Expect bounds mismatch.
+  Extension(classB).genericMethod<A>(a); // Expect bounds mismatch.
   Extension(classB).genericMethod<B>(a);
-  Extension<A>(classB).genericMethod(a);
-  Extension<A>(classB).genericMethod<A>(a);
-  Extension<A>(classB).genericMethod<B>(a);
-  Extension<B>(classB).genericMethod(a);
-  Extension<B>(classB).genericMethod<A>(a);
+  Extension<A>(classB).genericMethod(a); // Expect bounds mismatch.
+  Extension<A>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+  Extension<A>(classB).genericMethod<B>(a); // Expect bounds mismatch.
+  Extension<B>(classB).genericMethod(a); // Expect bounds mismatch.
+  Extension<B>(classB).genericMethod<A>(a); // Expect bounds mismatch.
   Extension<B>(classB).genericMethod<B>(a);
-}
\ No newline at end of file
+}
+
+final A a = new A();
+final Class<A> classA = new Class<A>();
+final field1 = classA.method(); // Expect method not found.
+final field2 = Extension(classA).method(); // Expect bounds mismatch.
+final field3 = Extension<A>(classA).method(); // Expect bounds mismatch.
+final field4 = Extension<B>(classA).method();
+final field5 = Extension(classA).genericMethod(a); // Expect bounds mismatch.
+final field6 = Extension(classA).genericMethod<A>(a); // Expect bounds mismatch.
+final field7 = Extension(classA).genericMethod<B>(a); // Expect bounds mismatch.
+final field8 = Extension<A>(classA).genericMethod(a); // Expect bounds mismatch.
+final field9 =
+    Extension<A>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+final field10 =
+    Extension<A>(classA).genericMethod<B>(a); // Expect bounds mismatch.
+final field11 =
+    Extension<B>(classA).genericMethod(a); // Expect bounds mismatch.
+final field12 =
+    Extension<B>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+final field13 = Extension<B>(classA).genericMethod<B>(a);
+
+final Class<B> classB = new Class<B>();
+final field14 = classB.method();
+final field15 = Extension(classB).method();
+final field16 = Extension<A>(classB).method(); // Expect bounds mismatch.
+final field17 = Extension<B>(classB).method();
+
+final field18 = classB.genericMethod(a); // Expect bounds mismatch.
+final field19 = classB.genericMethod<A>(a); // Expect bounds mismatch.
+final field20 = classB.genericMethod<B>(a);
+final field21 = Extension(classB).genericMethod(a); // Expect bounds mismatch.
+final field22 =
+    Extension(classB).genericMethod<A>(a); // Expect bounds mismatch.
+final field23 = Extension(classB).genericMethod<B>(a);
+final field24 =
+    Extension<A>(classB).genericMethod(a); // Expect bounds mismatch.
+final field25 =
+    Extension<A>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+final field26 =
+    Extension<A>(classB).genericMethod<B>(a); // Expect bounds mismatch.
+final field27 =
+    Extension<B>(classB).genericMethod(a); // Expect bounds mismatch.
+final field28 =
+    Extension<B>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+final field29 = Extension<B>(classB).genericMethod<B>(a);
diff --git a/pkg/front_end/testcases/extensions/check_bounds.dart.outline.expect b/pkg/front_end/testcases/extensions/check_bounds.dart.outline.expect
index f5164e8..533a05a 100644
--- a/pkg/front_end/testcases/extensions/check_bounds.dart.outline.expect
+++ b/pkg/front_end/testcases/extensions/check_bounds.dart.outline.expect
@@ -2,6 +2,7 @@
 import self as self;
 import "dart:core" as core;
 
+part check_bounds_lib.dart;
 class A extends core::Object {
   synthetic constructor •() → self::A*
     ;
@@ -20,6 +21,38 @@
   method genericMethod = self::Extension|genericMethod;
   tearoff genericMethod = self::Extension|get#genericMethod;
 }
+static final field self::A* a;
+static final field self::Class<self::A*>* classA;
+static final field dynamic field1;
+static final field dynamic field2;
+static final field dynamic field3;
+static final field dynamic field4;
+static final field dynamic field5;
+static final field dynamic field6;
+static final field dynamic field7;
+static final field dynamic field8;
+static final field dynamic field9;
+static final field dynamic field10;
+static final field dynamic field11;
+static final field dynamic field12;
+static final field dynamic field13;
+static final field self::Class<self::B*>* classB;
+static final field dynamic field14;
+static final field dynamic field15;
+static final field dynamic field16;
+static final field dynamic field17;
+static final field dynamic field18;
+static final field dynamic field19;
+static final field dynamic field20;
+static final field dynamic field21;
+static final field dynamic field22;
+static final field dynamic field23;
+static final field dynamic field24;
+static final field dynamic field25;
+static final field dynamic field26;
+static final field dynamic field27;
+static final field dynamic field28;
+static final field dynamic field29;
 static method Extension|method<T extends self::B* = dynamic>(final self::Class<self::Extension|method::T*>* #this) → dynamic
   ;
 static method Extension|get#method<T extends self::B* = dynamic>(final self::Class<self::Extension|get#method::T*>* #this) → () →* dynamic
@@ -32,3 +65,5 @@
   ;
 static method test() → dynamic
   ;
+static method /* from org-dartlang-testcase:///check_bounds_lib.dart */ testInPart() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/check_bounds.dart.strong.expect b/pkg/front_end/testcases/extensions/check_bounds.dart.strong.expect
index c99820d..ee82d11 100644
--- a/pkg/front_end/testcases/extensions/check_bounds.dart.strong.expect
+++ b/pkg/front_end/testcases/extensions/check_bounds.dart.strong.expect
@@ -2,106 +2,811 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/extensions/check_bounds.dart:23:10: Error: The method 'method' isn't defined for the class 'Class<A>'.
+// pkg/front_end/testcases/extensions/check_bounds.dart:24:10: Error: The method 'method' isn't defined for the class 'Class<A>'.
+//  - 'Class' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'method'.
+//   classA.method(); // Expect method not found.
+//          ^^^^^^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:25:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension(classA).method(); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:26:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classA).method(); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:28:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension(classA).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:28:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension(classA).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:29:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:29:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:30:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension(classA).genericMethod<B>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:31:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classA).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:31:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension<A>(classA).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:32:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:32:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:33:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classA).genericMethod<B>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:34:24: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension<B>(classA).genericMethod(a); // Expect bounds mismatch.
+//                        ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:35:24: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<B>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//                        ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:41:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classB).method(); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:44:10: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   classB.genericMethod(a); // Expect bounds mismatch.
+//          ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:45:10: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   classB.genericMethod<A>(a); // Expect bounds mismatch.
+//          ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:47:21: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension(classB).genericMethod(a); // Expect bounds mismatch.
+//                     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:48:21: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//                     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:50:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classB).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:50:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension<A>(classB).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:51:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:51:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:52:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classB).genericMethod<B>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:53:24: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension<B>(classB).genericMethod(a); // Expect bounds mismatch.
+//                        ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:54:24: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<B>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//                        ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:60:23: Error: The method 'method' isn't defined for the class 'Class<A>'.
+//  - 'Class' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'method'.
+// final field1 = classA.method(); // Expect method not found.
+//                       ^^^^^^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:61:16: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// final field2 = Extension(classA).method(); // Expect bounds mismatch.
+//                ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:62:16: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// final field3 = Extension<A>(classA).method(); // Expect bounds mismatch.
+//                ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:64:16: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// final field5 = Extension(classA).genericMethod(a); // Expect bounds mismatch.
+//                ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:64:16: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// final field5 = Extension(classA).genericMethod(a); // Expect bounds mismatch.
+//                ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:65:16: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// final field6 = Extension(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//                ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:65:16: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// final field6 = Extension(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//                ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:66:16: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// final field7 = Extension(classA).genericMethod<B>(a); // Expect bounds mismatch.
+//                ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:67:16: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// final field8 = Extension<A>(classA).genericMethod(a); // Expect bounds mismatch.
+//                ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:67:16: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// final field8 = Extension<A>(classA).genericMethod(a); // Expect bounds mismatch.
+//                ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:69:5: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//     Extension<A>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:69:5: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//     Extension<A>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:71:5: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//     Extension<A>(classA).genericMethod<B>(a); // Expect bounds mismatch.
+//     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:73:26: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//     Extension<B>(classA).genericMethod(a); // Expect bounds mismatch.
+//                          ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:75:26: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//     Extension<B>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//                          ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:81:17: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// final field16 = Extension<A>(classB).method(); // Expect bounds mismatch.
+//                 ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:84:24: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// final field18 = classB.genericMethod(a); // Expect bounds mismatch.
+//                        ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:85:24: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// final field19 = classB.genericMethod<A>(a); // Expect bounds mismatch.
+//                        ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:87:35: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// final field21 = Extension(classB).genericMethod(a); // Expect bounds mismatch.
+//                                   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:89:23: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//     Extension(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//                       ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:92:5: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//     Extension<A>(classB).genericMethod(a); // Expect bounds mismatch.
+//     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:92:5: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//     Extension<A>(classB).genericMethod(a); // Expect bounds mismatch.
+//     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:94:5: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//     Extension<A>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:94:5: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//     Extension<A>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:96:5: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//     Extension<A>(classB).genericMethod<B>(a); // Expect bounds mismatch.
+//     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:98:26: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//     Extension<B>(classB).genericMethod(a); // Expect bounds mismatch.
+//                          ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:100:26: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//     Extension<B>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//                          ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:11:10: Error: The method 'method' isn't defined for the class 'Class<A>'.
 //  - 'Class' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 //  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 // Try correcting the name to the name of an existing method, or defining a method named 'method'.
 //   classA.method();
 //          ^^^^^^
 //
-// pkg/front_end/testcases/extensions/check_bounds.dart:24:21: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:12:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
 //  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 //  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 // Try specifying type arguments explicitly so that they conform to the bounds.
-//   Extension(classA).method();
-//                     ^
-// pkg/front_end/testcases/extensions/check_bounds.dart:10:21: Context: This is the type variable whose bound isn't conformed to.
+//   Extension(classA).method(); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
 // extension Extension<T extends B> on Class<T> {
 //                     ^
 //
-// pkg/front_end/testcases/extensions/check_bounds.dart:25:24: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
-//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
-//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-//   Extension<A>(classA).method();
-//                        ^
-// pkg/front_end/testcases/extensions/check_bounds.dart:10:21: Context: This is the type variable whose bound isn't conformed to.
-// extension Extension<T extends B> on Class<T> {
-//                     ^
-//
-// pkg/front_end/testcases/extensions/check_bounds.dart:31:24: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
-//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
-//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-//   Extension<A>(classB).method();
-//                        ^
-// pkg/front_end/testcases/extensions/check_bounds.dart:10:21: Context: This is the type variable whose bound isn't conformed to.
-// extension Extension<T extends B> on Class<T> {
-//                     ^
-//
-// pkg/front_end/testcases/extensions/check_bounds.dart:34:10: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:13:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
 //  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 //  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 // Try changing type arguments so that they conform to the bounds.
-//   classB.genericMethod(a);
-//          ^
-// pkg/front_end/testcases/extensions/check_bounds.dart:12:17: Context: This is the type variable whose bound isn't conformed to.
-//   genericMethod<S extends B>(S s) {}
-//                 ^
-//
-// pkg/front_end/testcases/extensions/check_bounds.dart:35:10: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
-//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
-//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
-// Try changing type arguments so that they conform to the bounds.
-//   classB.genericMethod<A>(a);
-//          ^
-// pkg/front_end/testcases/extensions/check_bounds.dart:12:17: Context: This is the type variable whose bound isn't conformed to.
-//   genericMethod<S extends B>(S s) {}
-//                 ^
-//
-// pkg/front_end/testcases/extensions/check_bounds.dart:37:21: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
-//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
-//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-//   Extension(classB).genericMethod(a);
-//                     ^
-// pkg/front_end/testcases/extensions/check_bounds.dart:12:17: Context: This is the type variable whose bound isn't conformed to.
-//   genericMethod<S extends B>(S s) {}
-//                 ^
-//
-// pkg/front_end/testcases/extensions/check_bounds.dart:40:24: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
-//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
-//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-//   Extension<A>(classB).genericMethod(a);
-//                        ^
-// pkg/front_end/testcases/extensions/check_bounds.dart:10:21: Context: This is the type variable whose bound isn't conformed to.
+//   Extension<A>(classA).method(); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
 // extension Extension<T extends B> on Class<T> {
 //                     ^
 //
-// pkg/front_end/testcases/extensions/check_bounds.dart:40:24: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:15:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
 //  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 //  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 // Try specifying type arguments explicitly so that they conform to the bounds.
-//   Extension<A>(classB).genericMethod(a);
-//                        ^
-// pkg/front_end/testcases/extensions/check_bounds.dart:12:17: Context: This is the type variable whose bound isn't conformed to.
+//   Extension(classA).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:15:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension(classA).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
 //   genericMethod<S extends B>(S s) {}
 //                 ^
 //
-// pkg/front_end/testcases/extensions/check_bounds.dart:43:24: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:16:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
 //  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 //  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 // Try specifying type arguments explicitly so that they conform to the bounds.
-//   Extension<B>(classB).genericMethod(a);
+//   Extension(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:16:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:17:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension(classA).genericMethod<B>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:18:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classA).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:18:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension<A>(classA).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:19:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:19:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:20:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classA).genericMethod<B>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:21:24: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension<B>(classA).genericMethod(a); // Expect bounds mismatch.
 //                        ^
-// pkg/front_end/testcases/extensions/check_bounds.dart:12:17: Context: This is the type variable whose bound isn't conformed to.
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:22:24: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<B>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//                        ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:28:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classB).method(); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:31:10: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   classB.genericMethod(a); // Expect bounds mismatch.
+//          ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:32:10: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   classB.genericMethod<A>(a); // Expect bounds mismatch.
+//          ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:34:21: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension(classB).genericMethod(a); // Expect bounds mismatch.
+//                     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:35:21: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//                     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:37:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classB).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:37:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension<A>(classB).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:38:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:38:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:39:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classB).genericMethod<B>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:40:24: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension<B>(classB).genericMethod(a); // Expect bounds mismatch.
+//                        ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:41:24: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<B>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//                        ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
 //   genericMethod<S extends B>(S s) {}
 //                 ^
 //
 import self as self;
 import "dart:core" as core;
 
+part check_bounds_lib.dart;
 class A extends core::Object {
   synthetic constructor •() → self::A*
     : super core::Object::•()
@@ -123,6 +828,43 @@
   method genericMethod = self::Extension|genericMethod;
   tearoff genericMethod = self::Extension|get#genericMethod;
 }
+static final field self::A* a = new self::A::•();
+static final field self::Class<self::A*>* classA = new self::Class::•<self::A*>();
+static final field dynamic field1 = invalid-expression "pkg/front_end/testcases/extensions/check_bounds.dart:60:23: Error: The method 'method' isn't defined for the class 'Class<A>'.
+ - 'Class' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+ - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'method'.
+final field1 = classA.method(); // Expect method not found.
+                      ^^^^^^";
+static final field dynamic field2 = self::Extension|method<self::A*>(self::classA);
+static final field dynamic field3 = self::Extension|method<self::A*>(self::classA);
+static final field dynamic field4 = self::Extension|method<self::B*>(self::classA as{TypeError} self::Class<self::B*>*);
+static final field dynamic field5 = self::Extension|genericMethod<self::A*, self::A*>(self::classA, self::a);
+static final field dynamic field6 = self::Extension|genericMethod<self::A*, self::A*>(self::classA, self::a);
+static final field dynamic field7 = self::Extension|genericMethod<self::A*, self::B*>(self::classA, self::a as{TypeError} self::B*);
+static final field dynamic field8 = self::Extension|genericMethod<self::A*, self::A*>(self::classA, self::a);
+static final field dynamic field9 = self::Extension|genericMethod<self::A*, self::A*>(self::classA, self::a);
+static final field dynamic field10 = self::Extension|genericMethod<self::A*, self::B*>(self::classA, self::a as{TypeError} self::B*);
+static final field dynamic field11 = self::Extension|genericMethod<self::B*, self::A*>(self::classA as{TypeError} self::Class<self::B*>*, self::a);
+static final field dynamic field12 = self::Extension|genericMethod<self::B*, self::A*>(self::classA as{TypeError} self::Class<self::B*>*, self::a);
+static final field dynamic field13 = self::Extension|genericMethod<self::B*, self::B*>(self::classA as{TypeError} self::Class<self::B*>*, self::a as{TypeError} self::B*);
+static final field self::Class<self::B*>* classB = new self::Class::•<self::B*>();
+static final field dynamic field14 = self::Extension|method<self::B*>(self::classB);
+static final field dynamic field15 = self::Extension|method<self::B*>(self::classB);
+static final field dynamic field16 = self::Extension|method<self::A*>(self::classB);
+static final field dynamic field17 = self::Extension|method<self::B*>(self::classB);
+static final field dynamic field18 = self::Extension|genericMethod<self::B*, self::A*>(self::classB, self::a);
+static final field dynamic field19 = self::Extension|genericMethod<self::B*, self::A*>(self::classB, self::a);
+static final field dynamic field20 = self::Extension|genericMethod<self::B*, self::B*>(self::classB, self::a as{TypeError} self::B*);
+static final field dynamic field21 = self::Extension|genericMethod<self::B*, self::A*>(self::classB, self::a);
+static final field dynamic field22 = self::Extension|genericMethod<self::B*, self::A*>(self::classB, self::a);
+static final field dynamic field23 = self::Extension|genericMethod<self::B*, self::B*>(self::classB, self::a as{TypeError} self::B*);
+static final field dynamic field24 = self::Extension|genericMethod<self::A*, self::A*>(self::classB, self::a);
+static final field dynamic field25 = self::Extension|genericMethod<self::A*, self::A*>(self::classB, self::a);
+static final field dynamic field26 = self::Extension|genericMethod<self::A*, self::B*>(self::classB, self::a as{TypeError} self::B*);
+static final field dynamic field27 = self::Extension|genericMethod<self::B*, self::A*>(self::classB, self::a);
+static final field dynamic field28 = self::Extension|genericMethod<self::B*, self::A*>(self::classB, self::a);
+static final field dynamic field29 = self::Extension|genericMethod<self::B*, self::B*>(self::classB, self::a as{TypeError} self::B*);
 static method Extension|method<T extends self::B* = dynamic>(final self::Class<self::Extension|method::T*>* #this) → dynamic {}
 static method Extension|get#method<T extends self::B* = dynamic>(final self::Class<self::Extension|get#method::T*>* #this) → () →* dynamic
   return () → dynamic => self::Extension|method<self::Extension|get#method::T*>(#this);
@@ -133,7 +875,46 @@
 static method test() → dynamic {
   self::A* a;
   self::Class<self::A*>* classA = new self::Class::•<self::A*>();
-  invalid-expression "pkg/front_end/testcases/extensions/check_bounds.dart:23:10: Error: The method 'method' isn't defined for the class 'Class<A>'.
+  invalid-expression "pkg/front_end/testcases/extensions/check_bounds.dart:24:10: Error: The method 'method' isn't defined for the class 'Class<A>'.
+ - 'Class' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+ - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'method'.
+  classA.method(); // Expect method not found.
+         ^^^^^^";
+  self::Extension|method<self::A*>(classA);
+  self::Extension|method<self::A*>(classA);
+  self::Extension|method<self::B*>(classA as{TypeError} self::Class<self::B*>*);
+  self::Extension|genericMethod<self::A*, self::A*>(classA, a);
+  self::Extension|genericMethod<self::A*, self::A*>(classA, a);
+  self::Extension|genericMethod<self::A*, self::B*>(classA, a as{TypeError} self::B*);
+  self::Extension|genericMethod<self::A*, self::A*>(classA, a);
+  self::Extension|genericMethod<self::A*, self::A*>(classA, a);
+  self::Extension|genericMethod<self::A*, self::B*>(classA, a as{TypeError} self::B*);
+  self::Extension|genericMethod<self::B*, self::A*>(classA as{TypeError} self::Class<self::B*>*, a);
+  self::Extension|genericMethod<self::B*, self::A*>(classA as{TypeError} self::Class<self::B*>*, a);
+  self::Extension|genericMethod<self::B*, self::B*>(classA as{TypeError} self::Class<self::B*>*, a as{TypeError} self::B*);
+  self::Class<self::B*>* classB = new self::Class::•<self::B*>();
+  self::Extension|method<self::B*>(classB);
+  self::Extension|method<self::B*>(classB);
+  self::Extension|method<self::A*>(classB);
+  self::Extension|method<self::B*>(classB);
+  self::Extension|genericMethod<self::B*, self::A*>(classB, a);
+  self::Extension|genericMethod<self::B*, self::A*>(classB, a);
+  self::Extension|genericMethod<self::B*, self::B*>(classB, a as{TypeError} self::B*);
+  self::Extension|genericMethod<self::B*, self::A*>(classB, a);
+  self::Extension|genericMethod<self::B*, self::A*>(classB, a);
+  self::Extension|genericMethod<self::B*, self::B*>(classB, a as{TypeError} self::B*);
+  self::Extension|genericMethod<self::A*, self::A*>(classB, a);
+  self::Extension|genericMethod<self::A*, self::A*>(classB, a);
+  self::Extension|genericMethod<self::A*, self::B*>(classB, a as{TypeError} self::B*);
+  self::Extension|genericMethod<self::B*, self::A*>(classB, a);
+  self::Extension|genericMethod<self::B*, self::A*>(classB, a);
+  self::Extension|genericMethod<self::B*, self::B*>(classB, a as{TypeError} self::B*);
+}
+static method /* from org-dartlang-testcase:///check_bounds_lib.dart */ testInPart() → dynamic {
+  self::A* a;
+  self::Class<self::A*>* classA = new self::Class::•<self::A*>();
+  invalid-expression "pkg/front_end/testcases/extensions/check_bounds_lib.dart:11:10: Error: The method 'method' isn't defined for the class 'Class<A>'.
  - 'Class' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 Try correcting the name to the name of an existing method, or defining a method named 'method'.
@@ -142,6 +923,15 @@
   self::Extension|method<self::A*>(classA);
   self::Extension|method<self::A*>(classA);
   self::Extension|method<self::B*>(classA as{TypeError} self::Class<self::B*>*);
+  self::Extension|genericMethod<self::A*, self::A*>(classA, a);
+  self::Extension|genericMethod<self::A*, self::A*>(classA, a);
+  self::Extension|genericMethod<self::A*, self::B*>(classA, a as{TypeError} self::B*);
+  self::Extension|genericMethod<self::A*, self::A*>(classA, a);
+  self::Extension|genericMethod<self::A*, self::A*>(classA, a);
+  self::Extension|genericMethod<self::A*, self::B*>(classA, a as{TypeError} self::B*);
+  self::Extension|genericMethod<self::B*, self::A*>(classA as{TypeError} self::Class<self::B*>*, a);
+  self::Extension|genericMethod<self::B*, self::A*>(classA as{TypeError} self::Class<self::B*>*, a);
+  self::Extension|genericMethod<self::B*, self::B*>(classA as{TypeError} self::Class<self::B*>*, a as{TypeError} self::B*);
   self::Class<self::B*>* classB = new self::Class::•<self::B*>();
   self::Extension|method<self::B*>(classB);
   self::Extension|method<self::B*>(classB);
diff --git a/pkg/front_end/testcases/extensions/check_bounds.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/check_bounds.dart.strong.transformed.expect
index c99820d..ee82d11 100644
--- a/pkg/front_end/testcases/extensions/check_bounds.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/extensions/check_bounds.dart.strong.transformed.expect
@@ -2,106 +2,811 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/extensions/check_bounds.dart:23:10: Error: The method 'method' isn't defined for the class 'Class<A>'.
+// pkg/front_end/testcases/extensions/check_bounds.dart:24:10: Error: The method 'method' isn't defined for the class 'Class<A>'.
+//  - 'Class' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'method'.
+//   classA.method(); // Expect method not found.
+//          ^^^^^^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:25:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension(classA).method(); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:26:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classA).method(); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:28:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension(classA).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:28:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension(classA).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:29:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:29:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:30:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension(classA).genericMethod<B>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:31:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classA).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:31:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension<A>(classA).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:32:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:32:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:33:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classA).genericMethod<B>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:34:24: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension<B>(classA).genericMethod(a); // Expect bounds mismatch.
+//                        ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:35:24: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<B>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//                        ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:41:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classB).method(); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:44:10: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   classB.genericMethod(a); // Expect bounds mismatch.
+//          ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:45:10: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   classB.genericMethod<A>(a); // Expect bounds mismatch.
+//          ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:47:21: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension(classB).genericMethod(a); // Expect bounds mismatch.
+//                     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:48:21: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//                     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:50:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classB).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:50:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension<A>(classB).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:51:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:51:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:52:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classB).genericMethod<B>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:53:24: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension<B>(classB).genericMethod(a); // Expect bounds mismatch.
+//                        ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:54:24: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<B>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//                        ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:60:23: Error: The method 'method' isn't defined for the class 'Class<A>'.
+//  - 'Class' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named 'method'.
+// final field1 = classA.method(); // Expect method not found.
+//                       ^^^^^^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:61:16: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// final field2 = Extension(classA).method(); // Expect bounds mismatch.
+//                ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:62:16: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// final field3 = Extension<A>(classA).method(); // Expect bounds mismatch.
+//                ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:64:16: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// final field5 = Extension(classA).genericMethod(a); // Expect bounds mismatch.
+//                ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:64:16: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// final field5 = Extension(classA).genericMethod(a); // Expect bounds mismatch.
+//                ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:65:16: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// final field6 = Extension(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//                ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:65:16: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// final field6 = Extension(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//                ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:66:16: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// final field7 = Extension(classA).genericMethod<B>(a); // Expect bounds mismatch.
+//                ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:67:16: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// final field8 = Extension<A>(classA).genericMethod(a); // Expect bounds mismatch.
+//                ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:67:16: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// final field8 = Extension<A>(classA).genericMethod(a); // Expect bounds mismatch.
+//                ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:69:5: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//     Extension<A>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:69:5: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//     Extension<A>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:71:5: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//     Extension<A>(classA).genericMethod<B>(a); // Expect bounds mismatch.
+//     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:73:26: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//     Extension<B>(classA).genericMethod(a); // Expect bounds mismatch.
+//                          ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:75:26: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//     Extension<B>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//                          ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:81:17: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// final field16 = Extension<A>(classB).method(); // Expect bounds mismatch.
+//                 ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:84:24: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// final field18 = classB.genericMethod(a); // Expect bounds mismatch.
+//                        ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:85:24: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+// final field19 = classB.genericMethod<A>(a); // Expect bounds mismatch.
+//                        ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:87:35: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+// final field21 = Extension(classB).genericMethod(a); // Expect bounds mismatch.
+//                                   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:89:23: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//     Extension(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//                       ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:92:5: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//     Extension<A>(classB).genericMethod(a); // Expect bounds mismatch.
+//     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:92:5: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//     Extension<A>(classB).genericMethod(a); // Expect bounds mismatch.
+//     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:94:5: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//     Extension<A>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:94:5: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//     Extension<A>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:96:5: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//     Extension<A>(classB).genericMethod<B>(a); // Expect bounds mismatch.
+//     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:98:26: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//     Extension<B>(classB).genericMethod(a); // Expect bounds mismatch.
+//                          ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds.dart:100:26: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//     Extension<B>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//                          ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:11:10: Error: The method 'method' isn't defined for the class 'Class<A>'.
 //  - 'Class' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 //  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 // Try correcting the name to the name of an existing method, or defining a method named 'method'.
 //   classA.method();
 //          ^^^^^^
 //
-// pkg/front_end/testcases/extensions/check_bounds.dart:24:21: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:12:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
 //  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 //  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 // Try specifying type arguments explicitly so that they conform to the bounds.
-//   Extension(classA).method();
-//                     ^
-// pkg/front_end/testcases/extensions/check_bounds.dart:10:21: Context: This is the type variable whose bound isn't conformed to.
+//   Extension(classA).method(); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
 // extension Extension<T extends B> on Class<T> {
 //                     ^
 //
-// pkg/front_end/testcases/extensions/check_bounds.dart:25:24: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
-//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
-//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-//   Extension<A>(classA).method();
-//                        ^
-// pkg/front_end/testcases/extensions/check_bounds.dart:10:21: Context: This is the type variable whose bound isn't conformed to.
-// extension Extension<T extends B> on Class<T> {
-//                     ^
-//
-// pkg/front_end/testcases/extensions/check_bounds.dart:31:24: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
-//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
-//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-//   Extension<A>(classB).method();
-//                        ^
-// pkg/front_end/testcases/extensions/check_bounds.dart:10:21: Context: This is the type variable whose bound isn't conformed to.
-// extension Extension<T extends B> on Class<T> {
-//                     ^
-//
-// pkg/front_end/testcases/extensions/check_bounds.dart:34:10: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:13:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
 //  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 //  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 // Try changing type arguments so that they conform to the bounds.
-//   classB.genericMethod(a);
-//          ^
-// pkg/front_end/testcases/extensions/check_bounds.dart:12:17: Context: This is the type variable whose bound isn't conformed to.
-//   genericMethod<S extends B>(S s) {}
-//                 ^
-//
-// pkg/front_end/testcases/extensions/check_bounds.dart:35:10: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
-//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
-//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
-// Try changing type arguments so that they conform to the bounds.
-//   classB.genericMethod<A>(a);
-//          ^
-// pkg/front_end/testcases/extensions/check_bounds.dart:12:17: Context: This is the type variable whose bound isn't conformed to.
-//   genericMethod<S extends B>(S s) {}
-//                 ^
-//
-// pkg/front_end/testcases/extensions/check_bounds.dart:37:21: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
-//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
-//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-//   Extension(classB).genericMethod(a);
-//                     ^
-// pkg/front_end/testcases/extensions/check_bounds.dart:12:17: Context: This is the type variable whose bound isn't conformed to.
-//   genericMethod<S extends B>(S s) {}
-//                 ^
-//
-// pkg/front_end/testcases/extensions/check_bounds.dart:40:24: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
-//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
-//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
-// Try specifying type arguments explicitly so that they conform to the bounds.
-//   Extension<A>(classB).genericMethod(a);
-//                        ^
-// pkg/front_end/testcases/extensions/check_bounds.dart:10:21: Context: This is the type variable whose bound isn't conformed to.
+//   Extension<A>(classA).method(); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
 // extension Extension<T extends B> on Class<T> {
 //                     ^
 //
-// pkg/front_end/testcases/extensions/check_bounds.dart:40:24: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:15:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
 //  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 //  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 // Try specifying type arguments explicitly so that they conform to the bounds.
-//   Extension<A>(classB).genericMethod(a);
-//                        ^
-// pkg/front_end/testcases/extensions/check_bounds.dart:12:17: Context: This is the type variable whose bound isn't conformed to.
+//   Extension(classA).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:15:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension(classA).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
 //   genericMethod<S extends B>(S s) {}
 //                 ^
 //
-// pkg/front_end/testcases/extensions/check_bounds.dart:43:24: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:16:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
 //  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 //  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 // Try specifying type arguments explicitly so that they conform to the bounds.
-//   Extension<B>(classB).genericMethod(a);
+//   Extension(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:16:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:17:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension(classA).genericMethod<B>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:18:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classA).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:18:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension<A>(classA).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:19:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:19:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:20:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classA).genericMethod<B>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:21:24: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension<B>(classA).genericMethod(a); // Expect bounds mismatch.
 //                        ^
-// pkg/front_end/testcases/extensions/check_bounds.dart:12:17: Context: This is the type variable whose bound isn't conformed to.
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:22:24: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<B>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+//                        ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:28:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|method'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classB).method(); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:31:10: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   classB.genericMethod(a); // Expect bounds mismatch.
+//          ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:32:10: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   classB.genericMethod<A>(a); // Expect bounds mismatch.
+//          ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:34:21: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension(classB).genericMethod(a); // Expect bounds mismatch.
+//                     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:35:21: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//                     ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:37:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classB).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:37:3: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension<A>(classB).genericMethod(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:38:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:38:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:39:3: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'T' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<A>(classB).genericMethod<B>(a); // Expect bounds mismatch.
+//   ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:13:21: Context: This is the type variable whose bound isn't conformed to.
+// extension Extension<T extends B> on Class<T> {
+//                     ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:40:24: Error: Inferred type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try specifying type arguments explicitly so that they conform to the bounds.
+//   Extension<B>(classB).genericMethod(a); // Expect bounds mismatch.
+//                        ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
+//   genericMethod<S extends B>(S s) {}
+//                 ^
+//
+// pkg/front_end/testcases/extensions/check_bounds_lib.dart:41:24: Error: Type argument 'A' doesn't conform to the bound 'B' of the type variable 'S' on 'Extension|genericMethod'.
+//  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+//  - 'B' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+// Try changing type arguments so that they conform to the bounds.
+//   Extension<B>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+//                        ^
+// pkg/front_end/testcases/extensions/check_bounds.dart:15:17: Context: This is the type variable whose bound isn't conformed to.
 //   genericMethod<S extends B>(S s) {}
 //                 ^
 //
 import self as self;
 import "dart:core" as core;
 
+part check_bounds_lib.dart;
 class A extends core::Object {
   synthetic constructor •() → self::A*
     : super core::Object::•()
@@ -123,6 +828,43 @@
   method genericMethod = self::Extension|genericMethod;
   tearoff genericMethod = self::Extension|get#genericMethod;
 }
+static final field self::A* a = new self::A::•();
+static final field self::Class<self::A*>* classA = new self::Class::•<self::A*>();
+static final field dynamic field1 = invalid-expression "pkg/front_end/testcases/extensions/check_bounds.dart:60:23: Error: The method 'method' isn't defined for the class 'Class<A>'.
+ - 'Class' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+ - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'method'.
+final field1 = classA.method(); // Expect method not found.
+                      ^^^^^^";
+static final field dynamic field2 = self::Extension|method<self::A*>(self::classA);
+static final field dynamic field3 = self::Extension|method<self::A*>(self::classA);
+static final field dynamic field4 = self::Extension|method<self::B*>(self::classA as{TypeError} self::Class<self::B*>*);
+static final field dynamic field5 = self::Extension|genericMethod<self::A*, self::A*>(self::classA, self::a);
+static final field dynamic field6 = self::Extension|genericMethod<self::A*, self::A*>(self::classA, self::a);
+static final field dynamic field7 = self::Extension|genericMethod<self::A*, self::B*>(self::classA, self::a as{TypeError} self::B*);
+static final field dynamic field8 = self::Extension|genericMethod<self::A*, self::A*>(self::classA, self::a);
+static final field dynamic field9 = self::Extension|genericMethod<self::A*, self::A*>(self::classA, self::a);
+static final field dynamic field10 = self::Extension|genericMethod<self::A*, self::B*>(self::classA, self::a as{TypeError} self::B*);
+static final field dynamic field11 = self::Extension|genericMethod<self::B*, self::A*>(self::classA as{TypeError} self::Class<self::B*>*, self::a);
+static final field dynamic field12 = self::Extension|genericMethod<self::B*, self::A*>(self::classA as{TypeError} self::Class<self::B*>*, self::a);
+static final field dynamic field13 = self::Extension|genericMethod<self::B*, self::B*>(self::classA as{TypeError} self::Class<self::B*>*, self::a as{TypeError} self::B*);
+static final field self::Class<self::B*>* classB = new self::Class::•<self::B*>();
+static final field dynamic field14 = self::Extension|method<self::B*>(self::classB);
+static final field dynamic field15 = self::Extension|method<self::B*>(self::classB);
+static final field dynamic field16 = self::Extension|method<self::A*>(self::classB);
+static final field dynamic field17 = self::Extension|method<self::B*>(self::classB);
+static final field dynamic field18 = self::Extension|genericMethod<self::B*, self::A*>(self::classB, self::a);
+static final field dynamic field19 = self::Extension|genericMethod<self::B*, self::A*>(self::classB, self::a);
+static final field dynamic field20 = self::Extension|genericMethod<self::B*, self::B*>(self::classB, self::a as{TypeError} self::B*);
+static final field dynamic field21 = self::Extension|genericMethod<self::B*, self::A*>(self::classB, self::a);
+static final field dynamic field22 = self::Extension|genericMethod<self::B*, self::A*>(self::classB, self::a);
+static final field dynamic field23 = self::Extension|genericMethod<self::B*, self::B*>(self::classB, self::a as{TypeError} self::B*);
+static final field dynamic field24 = self::Extension|genericMethod<self::A*, self::A*>(self::classB, self::a);
+static final field dynamic field25 = self::Extension|genericMethod<self::A*, self::A*>(self::classB, self::a);
+static final field dynamic field26 = self::Extension|genericMethod<self::A*, self::B*>(self::classB, self::a as{TypeError} self::B*);
+static final field dynamic field27 = self::Extension|genericMethod<self::B*, self::A*>(self::classB, self::a);
+static final field dynamic field28 = self::Extension|genericMethod<self::B*, self::A*>(self::classB, self::a);
+static final field dynamic field29 = self::Extension|genericMethod<self::B*, self::B*>(self::classB, self::a as{TypeError} self::B*);
 static method Extension|method<T extends self::B* = dynamic>(final self::Class<self::Extension|method::T*>* #this) → dynamic {}
 static method Extension|get#method<T extends self::B* = dynamic>(final self::Class<self::Extension|get#method::T*>* #this) → () →* dynamic
   return () → dynamic => self::Extension|method<self::Extension|get#method::T*>(#this);
@@ -133,7 +875,46 @@
 static method test() → dynamic {
   self::A* a;
   self::Class<self::A*>* classA = new self::Class::•<self::A*>();
-  invalid-expression "pkg/front_end/testcases/extensions/check_bounds.dart:23:10: Error: The method 'method' isn't defined for the class 'Class<A>'.
+  invalid-expression "pkg/front_end/testcases/extensions/check_bounds.dart:24:10: Error: The method 'method' isn't defined for the class 'Class<A>'.
+ - 'Class' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+ - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
+Try correcting the name to the name of an existing method, or defining a method named 'method'.
+  classA.method(); // Expect method not found.
+         ^^^^^^";
+  self::Extension|method<self::A*>(classA);
+  self::Extension|method<self::A*>(classA);
+  self::Extension|method<self::B*>(classA as{TypeError} self::Class<self::B*>*);
+  self::Extension|genericMethod<self::A*, self::A*>(classA, a);
+  self::Extension|genericMethod<self::A*, self::A*>(classA, a);
+  self::Extension|genericMethod<self::A*, self::B*>(classA, a as{TypeError} self::B*);
+  self::Extension|genericMethod<self::A*, self::A*>(classA, a);
+  self::Extension|genericMethod<self::A*, self::A*>(classA, a);
+  self::Extension|genericMethod<self::A*, self::B*>(classA, a as{TypeError} self::B*);
+  self::Extension|genericMethod<self::B*, self::A*>(classA as{TypeError} self::Class<self::B*>*, a);
+  self::Extension|genericMethod<self::B*, self::A*>(classA as{TypeError} self::Class<self::B*>*, a);
+  self::Extension|genericMethod<self::B*, self::B*>(classA as{TypeError} self::Class<self::B*>*, a as{TypeError} self::B*);
+  self::Class<self::B*>* classB = new self::Class::•<self::B*>();
+  self::Extension|method<self::B*>(classB);
+  self::Extension|method<self::B*>(classB);
+  self::Extension|method<self::A*>(classB);
+  self::Extension|method<self::B*>(classB);
+  self::Extension|genericMethod<self::B*, self::A*>(classB, a);
+  self::Extension|genericMethod<self::B*, self::A*>(classB, a);
+  self::Extension|genericMethod<self::B*, self::B*>(classB, a as{TypeError} self::B*);
+  self::Extension|genericMethod<self::B*, self::A*>(classB, a);
+  self::Extension|genericMethod<self::B*, self::A*>(classB, a);
+  self::Extension|genericMethod<self::B*, self::B*>(classB, a as{TypeError} self::B*);
+  self::Extension|genericMethod<self::A*, self::A*>(classB, a);
+  self::Extension|genericMethod<self::A*, self::A*>(classB, a);
+  self::Extension|genericMethod<self::A*, self::B*>(classB, a as{TypeError} self::B*);
+  self::Extension|genericMethod<self::B*, self::A*>(classB, a);
+  self::Extension|genericMethod<self::B*, self::A*>(classB, a);
+  self::Extension|genericMethod<self::B*, self::B*>(classB, a as{TypeError} self::B*);
+}
+static method /* from org-dartlang-testcase:///check_bounds_lib.dart */ testInPart() → dynamic {
+  self::A* a;
+  self::Class<self::A*>* classA = new self::Class::•<self::A*>();
+  invalid-expression "pkg/front_end/testcases/extensions/check_bounds_lib.dart:11:10: Error: The method 'method' isn't defined for the class 'Class<A>'.
  - 'Class' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
  - 'A' is from 'pkg/front_end/testcases/extensions/check_bounds.dart'.
 Try correcting the name to the name of an existing method, or defining a method named 'method'.
@@ -142,6 +923,15 @@
   self::Extension|method<self::A*>(classA);
   self::Extension|method<self::A*>(classA);
   self::Extension|method<self::B*>(classA as{TypeError} self::Class<self::B*>*);
+  self::Extension|genericMethod<self::A*, self::A*>(classA, a);
+  self::Extension|genericMethod<self::A*, self::A*>(classA, a);
+  self::Extension|genericMethod<self::A*, self::B*>(classA, a as{TypeError} self::B*);
+  self::Extension|genericMethod<self::A*, self::A*>(classA, a);
+  self::Extension|genericMethod<self::A*, self::A*>(classA, a);
+  self::Extension|genericMethod<self::A*, self::B*>(classA, a as{TypeError} self::B*);
+  self::Extension|genericMethod<self::B*, self::A*>(classA as{TypeError} self::Class<self::B*>*, a);
+  self::Extension|genericMethod<self::B*, self::A*>(classA as{TypeError} self::Class<self::B*>*, a);
+  self::Extension|genericMethod<self::B*, self::B*>(classA as{TypeError} self::Class<self::B*>*, a as{TypeError} self::B*);
   self::Class<self::B*>* classB = new self::Class::•<self::B*>();
   self::Extension|method<self::B*>(classB);
   self::Extension|method<self::B*>(classB);
diff --git a/pkg/front_end/testcases/extensions/check_bounds_lib.dart b/pkg/front_end/testcases/extensions/check_bounds_lib.dart
new file mode 100644
index 0000000..3637ebe
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/check_bounds_lib.dart
@@ -0,0 +1,43 @@
+// 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 'check_bounds.dart';
+
+testInPart() {
+  A a;
+
+  Class<A> classA = new Class<A>();
+  classA.method();
+  Extension(classA).method(); // Expect bounds mismatch.
+  Extension<A>(classA).method(); // Expect bounds mismatch.
+  Extension<B>(classA).method();
+  Extension(classA).genericMethod(a); // Expect bounds mismatch.
+  Extension(classA).genericMethod<A>(a); // Expect bounds mismatch.
+  Extension(classA).genericMethod<B>(a); // Expect bounds mismatch.
+  Extension<A>(classA).genericMethod(a); // Expect bounds mismatch.
+  Extension<A>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+  Extension<A>(classA).genericMethod<B>(a); // Expect bounds mismatch.
+  Extension<B>(classA).genericMethod(a); // Expect bounds mismatch.
+  Extension<B>(classA).genericMethod<A>(a); // Expect bounds mismatch.
+  Extension<B>(classA).genericMethod<B>(a);
+
+  Class<B> classB = new Class<B>();
+  classB.method();
+  Extension(classB).method();
+  Extension<A>(classB).method(); // Expect bounds mismatch.
+  Extension<B>(classB).method();
+
+  classB.genericMethod(a); // Expect bounds mismatch.
+  classB.genericMethod<A>(a); // Expect bounds mismatch.
+  classB.genericMethod<B>(a);
+  Extension(classB).genericMethod(a); // Expect bounds mismatch.
+  Extension(classB).genericMethod<A>(a); // Expect bounds mismatch.
+  Extension(classB).genericMethod<B>(a);
+  Extension<A>(classB).genericMethod(a); // Expect bounds mismatch.
+  Extension<A>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+  Extension<A>(classB).genericMethod<B>(a); // Expect bounds mismatch.
+  Extension<B>(classB).genericMethod(a); // Expect bounds mismatch.
+  Extension<B>(classB).genericMethod<A>(a); // Expect bounds mismatch.
+  Extension<B>(classB).genericMethod<B>(a);
+}
diff --git a/pkg/front_end/testcases/extensions/issue38600.dart b/pkg/front_end/testcases/extensions/issue38600.dart
new file mode 100644
index 0000000..d2014e2
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38600.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.
+
+class Class<T> {}
+
+extension try<T> on Class<T> {}
+
+main() {}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/issue38600.dart.outline.expect b/pkg/front_end/testcases/extensions/issue38600.dart.outline.expect
new file mode 100644
index 0000000..f633a2a
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38600.dart.outline.expect
@@ -0,0 +1,59 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:1: Error: Expected 'on' after this.
+// extension try<T> on Class<T> {}
+// ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:11: Error: Expected a type, but got 'try'.
+// extension try<T> on Class<T> {}
+//           ^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:11: Error: A extension declaration must have a body, even if it is empty.
+// Try adding an empty body.
+// extension try<T> on Class<T> {}
+//           ^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:11: Error: Expected an identifier, but got 'try'.
+// extension try<T> on Class<T> {}
+//           ^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:11: Error: A function declaration needs an explicit list of parameters.
+// Try adding a parameter list to the function declaration.
+// extension try<T> on Class<T> {}
+//           ^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:18: Error: Expected '{' before this.
+// extension try<T> on Class<T> {}
+//                  ^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:21: Error: A function declaration needs an explicit list of parameters.
+// Try adding a parameter list to the function declaration.
+// extension try<T> on Class<T> {}
+//                     ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:21: Error: 'Class' is already declared in this scope.
+// extension try<T> on Class<T> {}
+//                     ^^^^^
+// pkg/front_end/testcases/extensions/issue38600.dart:5:7: Context: Previous declaration of 'Class'.
+// class Class<T> {}
+//       ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:18: Error: Type 'on' not found.
+// extension try<T> on Class<T> {}
+//                  ^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::Class<self::Class::T*>*
+    ;
+}
+extension _extension#0 on invalid-type {
+}
+static method try<T extends core::Object* = dynamic>() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/issue38600.dart.strong.expect b/pkg/front_end/testcases/extensions/issue38600.dart.strong.expect
new file mode 100644
index 0000000..8101879
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38600.dart.strong.expect
@@ -0,0 +1,58 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:1: Error: Expected 'on' after this.
+// extension try<T> on Class<T> {}
+// ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:11: Error: Expected a type, but got 'try'.
+// extension try<T> on Class<T> {}
+//           ^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:11: Error: A extension declaration must have a body, even if it is empty.
+// Try adding an empty body.
+// extension try<T> on Class<T> {}
+//           ^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:11: Error: Expected an identifier, but got 'try'.
+// extension try<T> on Class<T> {}
+//           ^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:11: Error: A function declaration needs an explicit list of parameters.
+// Try adding a parameter list to the function declaration.
+// extension try<T> on Class<T> {}
+//           ^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:18: Error: Expected '{' before this.
+// extension try<T> on Class<T> {}
+//                  ^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:21: Error: A function declaration needs an explicit list of parameters.
+// Try adding a parameter list to the function declaration.
+// extension try<T> on Class<T> {}
+//                     ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:21: Error: 'Class' is already declared in this scope.
+// extension try<T> on Class<T> {}
+//                     ^^^^^
+// pkg/front_end/testcases/extensions/issue38600.dart:5:7: Context: Previous declaration of 'Class'.
+// class Class<T> {}
+//       ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:18: Error: Type 'on' not found.
+// extension try<T> on Class<T> {}
+//                  ^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::Class<self::Class::T*>*
+    : super core::Object::•()
+    ;
+}
+extension _extension#0 on invalid-type {
+}
+static method try<T extends core::Object* = dynamic>() → dynamic {}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extensions/issue38600.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/issue38600.dart.strong.transformed.expect
new file mode 100644
index 0000000..8101879
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38600.dart.strong.transformed.expect
@@ -0,0 +1,58 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:1: Error: Expected 'on' after this.
+// extension try<T> on Class<T> {}
+// ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:11: Error: Expected a type, but got 'try'.
+// extension try<T> on Class<T> {}
+//           ^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:11: Error: A extension declaration must have a body, even if it is empty.
+// Try adding an empty body.
+// extension try<T> on Class<T> {}
+//           ^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:11: Error: Expected an identifier, but got 'try'.
+// extension try<T> on Class<T> {}
+//           ^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:11: Error: A function declaration needs an explicit list of parameters.
+// Try adding a parameter list to the function declaration.
+// extension try<T> on Class<T> {}
+//           ^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:18: Error: Expected '{' before this.
+// extension try<T> on Class<T> {}
+//                  ^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:21: Error: A function declaration needs an explicit list of parameters.
+// Try adding a parameter list to the function declaration.
+// extension try<T> on Class<T> {}
+//                     ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:21: Error: 'Class' is already declared in this scope.
+// extension try<T> on Class<T> {}
+//                     ^^^^^
+// pkg/front_end/testcases/extensions/issue38600.dart:5:7: Context: Previous declaration of 'Class'.
+// class Class<T> {}
+//       ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38600.dart:7:18: Error: Type 'on' not found.
+// extension try<T> on Class<T> {}
+//                  ^^
+//
+import self as self;
+import "dart:core" as core;
+
+class Class<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::Class<self::Class::T*>*
+    : super core::Object::•()
+    ;
+}
+extension _extension#0 on invalid-type {
+}
+static method try<T extends core::Object* = dynamic>() → dynamic {}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/extensions/issue38712.dart b/pkg/front_end/testcases/extensions/issue38712.dart
new file mode 100644
index 0000000..511036f
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38712.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.
+
+extension C {
+}
+
+void main() {
+
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/issue38712.dart.outline.expect b/pkg/front_end/testcases/extensions/issue38712.dart.outline.expect
new file mode 100644
index 0000000..3f1a511
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38712.dart.outline.expect
@@ -0,0 +1,18 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/issue38712.dart:5:11: Error: Expected 'on' after this.
+// extension C {
+//           ^
+//
+// pkg/front_end/testcases/extensions/issue38712.dart:5:13: Error: Expected a type, but got '{'.
+// extension C {
+//             ^
+//
+import self as self;
+
+extension C on invalid-type {
+}
+static method main() → void
+  ;
diff --git a/pkg/front_end/testcases/extensions/issue38712.dart.strong.expect b/pkg/front_end/testcases/extensions/issue38712.dart.strong.expect
new file mode 100644
index 0000000..464cf79
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38712.dart.strong.expect
@@ -0,0 +1,17 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/issue38712.dart:5:11: Error: Expected 'on' after this.
+// extension C {
+//           ^
+//
+// pkg/front_end/testcases/extensions/issue38712.dart:5:13: Error: Expected a type, but got '{'.
+// extension C {
+//             ^
+//
+import self as self;
+
+extension C on invalid-type {
+}
+static method main() → void {}
diff --git a/pkg/front_end/testcases/extensions/issue38712.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/issue38712.dart.strong.transformed.expect
new file mode 100644
index 0000000..464cf79
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38712.dart.strong.transformed.expect
@@ -0,0 +1,17 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/issue38712.dart:5:11: Error: Expected 'on' after this.
+// extension C {
+//           ^
+//
+// pkg/front_end/testcases/extensions/issue38712.dart:5:13: Error: Expected a type, but got '{'.
+// extension C {
+//             ^
+//
+import self as self;
+
+extension C on invalid-type {
+}
+static method main() → void {}
diff --git a/pkg/front_end/testcases/extensions/issue38713.dart b/pkg/front_end/testcases/extensions/issue38713.dart
new file mode 100644
index 0000000..0006934
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38713.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.
+
+extension C on int {
+  static int property2;
+  static void set property2(int x) {}
+
+  static void set property3(int x) {}
+  int get property3 => 1;
+}
+
+void main() {
+  C.property2;
+  C.property2 = 42;
+  C.property3 = 42;
+  42.property3;
+}
diff --git a/pkg/front_end/testcases/extensions/issue38713.dart.outline.expect b/pkg/front_end/testcases/extensions/issue38713.dart.outline.expect
new file mode 100644
index 0000000..b1e807a
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38713.dart.outline.expect
@@ -0,0 +1,38 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/issue38713.dart:7:19: Error: Conflicts with member 'property2'.
+//   static void set property2(int x) {}
+//                   ^
+//
+// pkg/front_end/testcases/extensions/issue38713.dart:6:14: Error: Conflicts with setter 'property2'.
+//   static int property2;
+//              ^
+//
+// pkg/front_end/testcases/extensions/issue38713.dart:9:19: Error: Conflicts with member 'property3'.
+//   static void set property3(int x) {}
+//                   ^
+//
+// pkg/front_end/testcases/extensions/issue38713.dart:10:11: Error: Conflicts with setter 'property3'.
+//   int get property3 => 1;
+//           ^
+//
+import self as self;
+import "dart:core" as core;
+
+extension C on core::int* {
+  static field property2 = self::C|property2;
+  get property3 = self::C|get#property3;
+  static set property2 = set self::C|property2;
+  static set property3 = set self::C|property3;
+}
+static field core::int* C|property2;
+static set C|property2(core::int* x) → void
+  ;
+static set C|property3(core::int* x) → void
+  ;
+static method C|get#property3(final core::int* #this) → core::int*
+  ;
+static method main() → void
+  ;
diff --git a/pkg/front_end/testcases/extensions/issue38713.dart.strong.expect b/pkg/front_end/testcases/extensions/issue38713.dart.strong.expect
new file mode 100644
index 0000000..3f56d65
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38713.dart.strong.expect
@@ -0,0 +1,40 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/issue38713.dart:7:19: Error: Conflicts with member 'property2'.
+//   static void set property2(int x) {}
+//                   ^
+//
+// pkg/front_end/testcases/extensions/issue38713.dart:6:14: Error: Conflicts with setter 'property2'.
+//   static int property2;
+//              ^
+//
+// pkg/front_end/testcases/extensions/issue38713.dart:9:19: Error: Conflicts with member 'property3'.
+//   static void set property3(int x) {}
+//                   ^
+//
+// pkg/front_end/testcases/extensions/issue38713.dart:10:11: Error: Conflicts with setter 'property3'.
+//   int get property3 => 1;
+//           ^
+//
+import self as self;
+import "dart:core" as core;
+
+extension C on core::int* {
+  static field property2 = self::C|property2;
+  get property3 = self::C|get#property3;
+  static set property2 = set self::C|property2;
+  static set property3 = set self::C|property3;
+}
+static field core::int* C|property2;
+static set C|property2(core::int* x) → void {}
+static set C|property3(core::int* x) → void {}
+static method C|get#property3(final core::int* #this) → core::int*
+  return 1;
+static method main() → void {
+  self::C|property2;
+  self::C|property2 = 42;
+  self::C|property3 = 42;
+  self::C|get#property3(42);
+}
diff --git a/pkg/front_end/testcases/extensions/issue38713.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/issue38713.dart.strong.transformed.expect
new file mode 100644
index 0000000..3f56d65
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38713.dart.strong.transformed.expect
@@ -0,0 +1,40 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/issue38713.dart:7:19: Error: Conflicts with member 'property2'.
+//   static void set property2(int x) {}
+//                   ^
+//
+// pkg/front_end/testcases/extensions/issue38713.dart:6:14: Error: Conflicts with setter 'property2'.
+//   static int property2;
+//              ^
+//
+// pkg/front_end/testcases/extensions/issue38713.dart:9:19: Error: Conflicts with member 'property3'.
+//   static void set property3(int x) {}
+//                   ^
+//
+// pkg/front_end/testcases/extensions/issue38713.dart:10:11: Error: Conflicts with setter 'property3'.
+//   int get property3 => 1;
+//           ^
+//
+import self as self;
+import "dart:core" as core;
+
+extension C on core::int* {
+  static field property2 = self::C|property2;
+  get property3 = self::C|get#property3;
+  static set property2 = set self::C|property2;
+  static set property3 = set self::C|property3;
+}
+static field core::int* C|property2;
+static set C|property2(core::int* x) → void {}
+static set C|property3(core::int* x) → void {}
+static method C|get#property3(final core::int* #this) → core::int*
+  return 1;
+static method main() → void {
+  self::C|property2;
+  self::C|property2 = 42;
+  self::C|property3 = 42;
+  self::C|get#property3(42);
+}
diff --git a/pkg/front_end/testcases/extensions/issue38745.dart b/pkg/front_end/testcases/extensions/issue38745.dart
new file mode 100644
index 0000000..357a655
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38745.dart
@@ -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 file.
+
+class C<T> {
+}
+
+extension ext<T> on C<T> {
+  int field;
+
+  final int property = 42;
+
+  void set property(int value) {}
+
+  final int property2 = 42;
+
+  static void set property2(int value) {}
+
+  method() {
+    field;
+    field = 23;
+    property;
+    property = 23;
+    property2;
+    property2 = 23;
+  }
+}
+
+main() {
+}
+
+errors() {
+  C<int> c = new C<int>();
+  c.field;
+  c.field = 23;
+  c.property;
+  c.property = 23;
+  c.property2;
+  c.property2 = 23;
+  ext(c).field;
+  ext(c).field = 23;
+  ext(c).property;
+  ext(c).property = 23;
+  ext(c).property2;
+  ext(c).property2 = 23;
+  c.method();
+}
\ No newline at end of file
diff --git a/pkg/front_end/testcases/extensions/issue38745.dart.outline.expect b/pkg/front_end/testcases/extensions/issue38745.dart.outline.expect
new file mode 100644
index 0000000..0e1178c
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38745.dart.outline.expect
@@ -0,0 +1,58 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:9:7: Error: Extensions can't declare instance fields
+// Try removing the field declaration or making it a static field
+//   int field;
+//       ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:11:13: Error: Extensions can't declare instance fields
+// Try removing the field declaration or making it a static field
+//   final int property = 42;
+//             ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:15:13: Error: Extensions can't declare instance fields
+// Try removing the field declaration or making it a static field
+//   final int property2 = 42;
+//             ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:17:19: Error: Conflicts with member 'property2'.
+//   static void set property2(int value) {}
+//                   ^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:15:13: Error: Conflicts with setter 'property2'.
+//   final int property2 = 42;
+//             ^
+//
+import self as self;
+import "dart:core" as core;
+
+class C<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::C<self::C::T*>*
+    ;
+}
+extension ext<T extends core::Object* = dynamic> on self::C<T*>* {
+  field field = self::ext|field;
+  field property = self::ext|property;
+  field property2 = self::ext|property2;
+  method method = self::ext|method;
+  tearoff method = self::ext|get#method;
+  set property = self::ext|set#property;
+  static set property2 = set self::ext|property2;
+}
+static field core::int* ext|field;
+static final field core::int* ext|property;
+static final field core::int* ext|property2;
+static method ext|set#property<T extends core::Object* = dynamic>(final self::C<self::ext|set#property::T*>* #this, core::int* value) → void
+  ;
+static set ext|property2(core::int* value) → void
+  ;
+static method ext|method<T extends core::Object* = dynamic>(final self::C<self::ext|method::T*>* #this) → dynamic
+  ;
+static method ext|get#method<T extends core::Object* = dynamic>(final self::C<self::ext|get#method::T*>* #this) → () →* dynamic
+  return () → dynamic => self::ext|method<self::ext|get#method::T*>(#this);
+static method main() → dynamic
+  ;
+static method errors() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/issue38745.dart.strong.expect b/pkg/front_end/testcases/extensions/issue38745.dart.strong.expect
new file mode 100644
index 0000000..289a70d
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38745.dart.strong.expect
@@ -0,0 +1,186 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:9:7: Error: Extensions can't declare instance fields
+// Try removing the field declaration or making it a static field
+//   int field;
+//       ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:11:13: Error: Extensions can't declare instance fields
+// Try removing the field declaration or making it a static field
+//   final int property = 42;
+//             ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:15:13: Error: Extensions can't declare instance fields
+// Try removing the field declaration or making it a static field
+//   final int property2 = 42;
+//             ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:17:19: Error: Conflicts with member 'property2'.
+//   static void set property2(int value) {}
+//                   ^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:15:13: Error: Conflicts with setter 'property2'.
+//   final int property2 = 42;
+//             ^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:20:5: Error: Getter not found: 'field'.
+//     field;
+//     ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:21:5: Error: Setter not found: 'field'.
+//     field = 23;
+//     ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:22:5: Error: Getter not found: 'property'.
+//     property;
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:24:5: Error: Getter not found: 'property2'.
+//     property2;
+//     ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:25:5: Error: Setter not found: 'property2'.
+//     property2 = 23;
+//     ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:40:10: Error: Getter not found: 'field'.
+//   ext(c).field;
+//          ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:41:10: Error: Setter not found: 'field'.
+//   ext(c).field = 23;
+//          ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:42:10: Error: Getter not found: 'property'.
+//   ext(c).property;
+//          ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:44:10: Error: Getter not found: 'property2'.
+//   ext(c).property2;
+//          ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:45:10: Error: Setter not found: 'property2'.
+//   ext(c).property2 = 23;
+//          ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:34:5: Error: The getter 'field' isn't defined for the class 'C<int>'.
+//  - 'C' is from 'pkg/front_end/testcases/extensions/issue38745.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'field'.
+//   c.field;
+//     ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:35:5: Error: The setter 'field' isn't defined for the class 'C<int>'.
+//  - 'C' is from 'pkg/front_end/testcases/extensions/issue38745.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'field'.
+//   c.field = 23;
+//     ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:36:5: Error: The getter 'property' isn't defined for the class 'C<int>'.
+//  - 'C' is from 'pkg/front_end/testcases/extensions/issue38745.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'property'.
+//   c.property;
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:38:5: Error: The getter 'property2' isn't defined for the class 'C<int>'.
+//  - 'C' is from 'pkg/front_end/testcases/extensions/issue38745.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'property2'.
+//   c.property2;
+//     ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:39:5: Error: The setter 'property2' isn't defined for the class 'C<int>'.
+//  - 'C' is from 'pkg/front_end/testcases/extensions/issue38745.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'property2'.
+//   c.property2 = 23;
+//     ^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class C<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::C<self::C::T*>*
+    : super core::Object::•()
+    ;
+}
+extension ext<T extends core::Object* = dynamic> on self::C<T*>* {
+  field field = self::ext|field;
+  field property = self::ext|property;
+  field property2 = self::ext|property2;
+  method method = self::ext|method;
+  tearoff method = self::ext|get#method;
+  set property = self::ext|set#property;
+  static set property2 = set self::ext|property2;
+}
+static field core::int* ext|field;
+static final field core::int* ext|property = 42;
+static final field core::int* ext|property2 = 42;
+static method ext|set#property<T extends core::Object* = dynamic>(final self::C<self::ext|set#property::T*>* #this, core::int* value) → void {}
+static set ext|property2(core::int* value) → void {}
+static method ext|method<T extends core::Object* = dynamic>(final self::C<self::ext|method::T*>* #this) → dynamic {
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:20:5: Error: Getter not found: 'field'.
+    field;
+    ^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:21:5: Error: Setter not found: 'field'.
+    field = 23;
+    ^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:22:5: Error: Getter not found: 'property'.
+    property;
+    ^^^^^^^^";
+  self::ext|set#property<self::ext|method::T*>(#this, 23);
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:24:5: Error: Getter not found: 'property2'.
+    property2;
+    ^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:25:5: Error: Setter not found: 'property2'.
+    property2 = 23;
+    ^^^^^^^^^";
+}
+static method ext|get#method<T extends core::Object* = dynamic>(final self::C<self::ext|get#method::T*>* #this) → () →* dynamic
+  return () → dynamic => self::ext|method<self::ext|get#method::T*>(#this);
+static method main() → dynamic {}
+static method errors() → dynamic {
+  self::C<core::int*>* c = new self::C::•<core::int*>();
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:34:5: Error: The getter 'field' isn't defined for the class 'C<int>'.
+ - 'C' is from 'pkg/front_end/testcases/extensions/issue38745.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'field'.
+  c.field;
+    ^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:35:5: Error: The setter 'field' isn't defined for the class 'C<int>'.
+ - 'C' is from 'pkg/front_end/testcases/extensions/issue38745.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'field'.
+  c.field = 23;
+    ^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:36:5: Error: The getter 'property' isn't defined for the class 'C<int>'.
+ - 'C' is from 'pkg/front_end/testcases/extensions/issue38745.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'property'.
+  c.property;
+    ^^^^^^^^";
+  self::ext|set#property<core::int*>(c, 23);
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:38:5: Error: The getter 'property2' isn't defined for the class 'C<int>'.
+ - 'C' is from 'pkg/front_end/testcases/extensions/issue38745.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'property2'.
+  c.property2;
+    ^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:39:5: Error: The setter 'property2' isn't defined for the class 'C<int>'.
+ - 'C' is from 'pkg/front_end/testcases/extensions/issue38745.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'property2'.
+  c.property2 = 23;
+    ^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:40:10: Error: Getter not found: 'field'.
+  ext(c).field;
+         ^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:41:10: Error: Setter not found: 'field'.
+  ext(c).field = 23;
+         ^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:42:10: Error: Getter not found: 'property'.
+  ext(c).property;
+         ^^^^^^^^";
+  self::ext|set#property<core::int*>(c, 23);
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:44:10: Error: Getter not found: 'property2'.
+  ext(c).property2;
+         ^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:45:10: Error: Setter not found: 'property2'.
+  ext(c).property2 = 23;
+         ^^^^^^^^^";
+  self::ext|method<core::int*>(c);
+}
diff --git a/pkg/front_end/testcases/extensions/issue38745.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/issue38745.dart.strong.transformed.expect
new file mode 100644
index 0000000..289a70d
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38745.dart.strong.transformed.expect
@@ -0,0 +1,186 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:9:7: Error: Extensions can't declare instance fields
+// Try removing the field declaration or making it a static field
+//   int field;
+//       ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:11:13: Error: Extensions can't declare instance fields
+// Try removing the field declaration or making it a static field
+//   final int property = 42;
+//             ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:15:13: Error: Extensions can't declare instance fields
+// Try removing the field declaration or making it a static field
+//   final int property2 = 42;
+//             ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:17:19: Error: Conflicts with member 'property2'.
+//   static void set property2(int value) {}
+//                   ^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:15:13: Error: Conflicts with setter 'property2'.
+//   final int property2 = 42;
+//             ^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:20:5: Error: Getter not found: 'field'.
+//     field;
+//     ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:21:5: Error: Setter not found: 'field'.
+//     field = 23;
+//     ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:22:5: Error: Getter not found: 'property'.
+//     property;
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:24:5: Error: Getter not found: 'property2'.
+//     property2;
+//     ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:25:5: Error: Setter not found: 'property2'.
+//     property2 = 23;
+//     ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:40:10: Error: Getter not found: 'field'.
+//   ext(c).field;
+//          ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:41:10: Error: Setter not found: 'field'.
+//   ext(c).field = 23;
+//          ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:42:10: Error: Getter not found: 'property'.
+//   ext(c).property;
+//          ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:44:10: Error: Getter not found: 'property2'.
+//   ext(c).property2;
+//          ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:45:10: Error: Setter not found: 'property2'.
+//   ext(c).property2 = 23;
+//          ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:34:5: Error: The getter 'field' isn't defined for the class 'C<int>'.
+//  - 'C' is from 'pkg/front_end/testcases/extensions/issue38745.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'field'.
+//   c.field;
+//     ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:35:5: Error: The setter 'field' isn't defined for the class 'C<int>'.
+//  - 'C' is from 'pkg/front_end/testcases/extensions/issue38745.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'field'.
+//   c.field = 23;
+//     ^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:36:5: Error: The getter 'property' isn't defined for the class 'C<int>'.
+//  - 'C' is from 'pkg/front_end/testcases/extensions/issue38745.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'property'.
+//   c.property;
+//     ^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:38:5: Error: The getter 'property2' isn't defined for the class 'C<int>'.
+//  - 'C' is from 'pkg/front_end/testcases/extensions/issue38745.dart'.
+// Try correcting the name to the name of an existing getter, or defining a getter or field named 'property2'.
+//   c.property2;
+//     ^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38745.dart:39:5: Error: The setter 'property2' isn't defined for the class 'C<int>'.
+//  - 'C' is from 'pkg/front_end/testcases/extensions/issue38745.dart'.
+// Try correcting the name to the name of an existing setter, or defining a setter or field named 'property2'.
+//   c.property2 = 23;
+//     ^^^^^^^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class C<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::C<self::C::T*>*
+    : super core::Object::•()
+    ;
+}
+extension ext<T extends core::Object* = dynamic> on self::C<T*>* {
+  field field = self::ext|field;
+  field property = self::ext|property;
+  field property2 = self::ext|property2;
+  method method = self::ext|method;
+  tearoff method = self::ext|get#method;
+  set property = self::ext|set#property;
+  static set property2 = set self::ext|property2;
+}
+static field core::int* ext|field;
+static final field core::int* ext|property = 42;
+static final field core::int* ext|property2 = 42;
+static method ext|set#property<T extends core::Object* = dynamic>(final self::C<self::ext|set#property::T*>* #this, core::int* value) → void {}
+static set ext|property2(core::int* value) → void {}
+static method ext|method<T extends core::Object* = dynamic>(final self::C<self::ext|method::T*>* #this) → dynamic {
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:20:5: Error: Getter not found: 'field'.
+    field;
+    ^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:21:5: Error: Setter not found: 'field'.
+    field = 23;
+    ^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:22:5: Error: Getter not found: 'property'.
+    property;
+    ^^^^^^^^";
+  self::ext|set#property<self::ext|method::T*>(#this, 23);
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:24:5: Error: Getter not found: 'property2'.
+    property2;
+    ^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:25:5: Error: Setter not found: 'property2'.
+    property2 = 23;
+    ^^^^^^^^^";
+}
+static method ext|get#method<T extends core::Object* = dynamic>(final self::C<self::ext|get#method::T*>* #this) → () →* dynamic
+  return () → dynamic => self::ext|method<self::ext|get#method::T*>(#this);
+static method main() → dynamic {}
+static method errors() → dynamic {
+  self::C<core::int*>* c = new self::C::•<core::int*>();
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:34:5: Error: The getter 'field' isn't defined for the class 'C<int>'.
+ - 'C' is from 'pkg/front_end/testcases/extensions/issue38745.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'field'.
+  c.field;
+    ^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:35:5: Error: The setter 'field' isn't defined for the class 'C<int>'.
+ - 'C' is from 'pkg/front_end/testcases/extensions/issue38745.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'field'.
+  c.field = 23;
+    ^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:36:5: Error: The getter 'property' isn't defined for the class 'C<int>'.
+ - 'C' is from 'pkg/front_end/testcases/extensions/issue38745.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'property'.
+  c.property;
+    ^^^^^^^^";
+  self::ext|set#property<core::int*>(c, 23);
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:38:5: Error: The getter 'property2' isn't defined for the class 'C<int>'.
+ - 'C' is from 'pkg/front_end/testcases/extensions/issue38745.dart'.
+Try correcting the name to the name of an existing getter, or defining a getter or field named 'property2'.
+  c.property2;
+    ^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:39:5: Error: The setter 'property2' isn't defined for the class 'C<int>'.
+ - 'C' is from 'pkg/front_end/testcases/extensions/issue38745.dart'.
+Try correcting the name to the name of an existing setter, or defining a setter or field named 'property2'.
+  c.property2 = 23;
+    ^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:40:10: Error: Getter not found: 'field'.
+  ext(c).field;
+         ^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:41:10: Error: Setter not found: 'field'.
+  ext(c).field = 23;
+         ^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:42:10: Error: Getter not found: 'property'.
+  ext(c).property;
+         ^^^^^^^^";
+  self::ext|set#property<core::int*>(c, 23);
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:44:10: Error: Getter not found: 'property2'.
+  ext(c).property2;
+         ^^^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38745.dart:45:10: Error: Setter not found: 'property2'.
+  ext(c).property2 = 23;
+         ^^^^^^^^^";
+  self::ext|method<core::int*>(c);
+}
diff --git a/pkg/front_end/testcases/extensions/issue38745.dart.type_promotion.expect b/pkg/front_end/testcases/extensions/issue38745.dart.type_promotion.expect
new file mode 100644
index 0000000..02c6ac8
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38745.dart.type_promotion.expect
@@ -0,0 +1,9 @@
+pkg/front_end/testcases/extensions/issue38745.dart:21:11: Context: Write to field@266
+    field = 23;
+          ^
+pkg/front_end/testcases/extensions/issue38745.dart:23:14: Context: Write to property@286
+    property = 23;
+             ^
+pkg/front_end/testcases/extensions/issue38745.dart:25:15: Context: Write to property2@349
+    property2 = 23;
+              ^
diff --git a/pkg/front_end/testcases/extensions/issue38750.dart b/pkg/front_end/testcases/extensions/issue38750.dart
new file mode 100644
index 0000000..46f0bc6
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38750.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.
+
+import 'issue38750_lib1.dart';
+import 'issue38750_lib2.dart';
+
+main() {}
+
+errors() {
+  C c = new C();
+  c._foo();
+  C._staticFoo();
+  c.foo();
+  C.staticFoo();
+  c._bar();
+}
diff --git a/pkg/front_end/testcases/extensions/issue38750.dart.outline.expect b/pkg/front_end/testcases/extensions/issue38750.dart.outline.expect
new file mode 100644
index 0000000..3852560
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38750.dart.outline.expect
@@ -0,0 +1,43 @@
+library;
+import self as self;
+
+import "org-dartlang-testcase:///issue38750_lib1.dart";
+import "org-dartlang-testcase:///issue38750_lib2.dart";
+
+static method main() → dynamic
+  ;
+static method errors() → dynamic
+  ;
+
+library;
+import self as self2;
+import "dart:core" as core;
+
+class C extends core::Object {
+  synthetic constructor •() → self2::C*
+    ;
+  method foo() → dynamic
+    ;
+  method _foo() → dynamic
+    ;
+  static method _staticFoo() → dynamic
+    ;
+  static method staticFoo() → dynamic
+    ;
+}
+extension ext on self2::C* {
+  method _bar = self2::ext|_bar;
+  tearoff _bar = self2::ext|get#_bar;
+}
+static method ext|_bar(final self2::C* #this) → dynamic
+  ;
+static method ext|get#_bar(final self2::C* #this) → () →* dynamic
+  return () → dynamic => self2::ext|_bar(#this);
+
+library;
+import self as self3;
+
+import "org-dartlang-testcase:///issue38750_lib1.dart";
+
+static method errors() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/issue38750.dart.strong.expect b/pkg/front_end/testcases/extensions/issue38750.dart.strong.expect
new file mode 100644
index 0000000..6b017ad
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38750.dart.strong.expect
@@ -0,0 +1,108 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/issue38750.dart:13:5: Error: Method not found: 'C._staticFoo'.
+//   C._staticFoo();
+//     ^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38750.dart:12:5: Error: The method '_foo' isn't defined for the class 'C'.
+//  - 'C' is from 'pkg/front_end/testcases/extensions/issue38750_lib1.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named '_foo'.
+//   c._foo();
+//     ^^^^
+//
+// pkg/front_end/testcases/extensions/issue38750.dart:16:5: Error: The method '_bar' isn't defined for the class 'C'.
+//  - 'C' is from 'pkg/front_end/testcases/extensions/issue38750_lib1.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named '_bar'.
+//   c._bar();
+//     ^^^^
+//
+import self as self;
+import "issue38750_lib1.dart" as iss;
+
+import "org-dartlang-testcase:///issue38750_lib1.dart";
+import "org-dartlang-testcase:///issue38750_lib2.dart";
+
+static method main() → dynamic {}
+static method errors() → dynamic {
+  iss::C* c = new iss::C::•();
+  invalid-expression "pkg/front_end/testcases/extensions/issue38750.dart:12:5: Error: The method '_foo' isn't defined for the class 'C'.
+ - 'C' is from 'pkg/front_end/testcases/extensions/issue38750_lib1.dart'.
+Try correcting the name to the name of an existing method, or defining a method named '_foo'.
+  c._foo();
+    ^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38750.dart:13:5: Error: Method not found: 'C._staticFoo'.
+  C._staticFoo();
+    ^^^^^^^^^^";
+  c.{iss::C::foo}();
+  iss::C::staticFoo();
+  invalid-expression "pkg/front_end/testcases/extensions/issue38750.dart:16:5: Error: The method '_bar' isn't defined for the class 'C'.
+ - 'C' is from 'pkg/front_end/testcases/extensions/issue38750_lib1.dart'.
+Try correcting the name to the name of an existing method, or defining a method named '_bar'.
+  c._bar();
+    ^^^^";
+}
+
+library;
+import self as iss;
+import "dart:core" as core;
+
+class C extends core::Object {
+  synthetic constructor •() → iss::C*
+    : super core::Object::•()
+    ;
+  method foo() → dynamic
+    return this.{iss::C::_foo}();
+  method _foo() → dynamic {
+    try {
+      throw "producing a stack trace";
+    }
+    on dynamic catch(final dynamic e, final core::StackTrace* s) {
+      core::print(s);
+    }
+  }
+  static method _staticFoo() → dynamic {
+    core::print("_staticFoo");
+  }
+  static method staticFoo() → dynamic
+    return iss::C::_staticFoo();
+}
+extension ext on iss::C* {
+  method _bar = iss::ext|_bar;
+  tearoff _bar = iss::ext|get#_bar;
+}
+static method ext|_bar(final iss::C* #this) → dynamic {
+  try {
+    throw "producing a stack trace";
+  }
+  on dynamic catch(final dynamic e, final core::StackTrace* s) {
+    core::print(s);
+  }
+}
+static method ext|get#_bar(final iss::C* #this) → () →* dynamic
+  return () → dynamic => iss::ext|_bar(#this);
+
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/issue38750_lib2.dart:9:5: Error: The method '_bar' isn't defined for the class 'C'.
+//  - 'C' is from 'pkg/front_end/testcases/extensions/issue38750_lib1.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named '_bar'.
+//   c._bar();
+//     ^^^^
+//
+import self as self2;
+import "issue38750_lib1.dart" as iss;
+
+import "org-dartlang-testcase:///issue38750_lib1.dart";
+
+static method errors() → dynamic {
+  iss::C* c = new iss::C::•();
+  invalid-expression "pkg/front_end/testcases/extensions/issue38750_lib2.dart:9:5: Error: The method '_bar' isn't defined for the class 'C'.
+ - 'C' is from 'pkg/front_end/testcases/extensions/issue38750_lib1.dart'.
+Try correcting the name to the name of an existing method, or defining a method named '_bar'.
+  c._bar();
+    ^^^^";
+}
diff --git a/pkg/front_end/testcases/extensions/issue38750.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/issue38750.dart.strong.transformed.expect
new file mode 100644
index 0000000..6b017ad
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38750.dart.strong.transformed.expect
@@ -0,0 +1,108 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/issue38750.dart:13:5: Error: Method not found: 'C._staticFoo'.
+//   C._staticFoo();
+//     ^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/issue38750.dart:12:5: Error: The method '_foo' isn't defined for the class 'C'.
+//  - 'C' is from 'pkg/front_end/testcases/extensions/issue38750_lib1.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named '_foo'.
+//   c._foo();
+//     ^^^^
+//
+// pkg/front_end/testcases/extensions/issue38750.dart:16:5: Error: The method '_bar' isn't defined for the class 'C'.
+//  - 'C' is from 'pkg/front_end/testcases/extensions/issue38750_lib1.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named '_bar'.
+//   c._bar();
+//     ^^^^
+//
+import self as self;
+import "issue38750_lib1.dart" as iss;
+
+import "org-dartlang-testcase:///issue38750_lib1.dart";
+import "org-dartlang-testcase:///issue38750_lib2.dart";
+
+static method main() → dynamic {}
+static method errors() → dynamic {
+  iss::C* c = new iss::C::•();
+  invalid-expression "pkg/front_end/testcases/extensions/issue38750.dart:12:5: Error: The method '_foo' isn't defined for the class 'C'.
+ - 'C' is from 'pkg/front_end/testcases/extensions/issue38750_lib1.dart'.
+Try correcting the name to the name of an existing method, or defining a method named '_foo'.
+  c._foo();
+    ^^^^";
+  invalid-expression "pkg/front_end/testcases/extensions/issue38750.dart:13:5: Error: Method not found: 'C._staticFoo'.
+  C._staticFoo();
+    ^^^^^^^^^^";
+  c.{iss::C::foo}();
+  iss::C::staticFoo();
+  invalid-expression "pkg/front_end/testcases/extensions/issue38750.dart:16:5: Error: The method '_bar' isn't defined for the class 'C'.
+ - 'C' is from 'pkg/front_end/testcases/extensions/issue38750_lib1.dart'.
+Try correcting the name to the name of an existing method, or defining a method named '_bar'.
+  c._bar();
+    ^^^^";
+}
+
+library;
+import self as iss;
+import "dart:core" as core;
+
+class C extends core::Object {
+  synthetic constructor •() → iss::C*
+    : super core::Object::•()
+    ;
+  method foo() → dynamic
+    return this.{iss::C::_foo}();
+  method _foo() → dynamic {
+    try {
+      throw "producing a stack trace";
+    }
+    on dynamic catch(final dynamic e, final core::StackTrace* s) {
+      core::print(s);
+    }
+  }
+  static method _staticFoo() → dynamic {
+    core::print("_staticFoo");
+  }
+  static method staticFoo() → dynamic
+    return iss::C::_staticFoo();
+}
+extension ext on iss::C* {
+  method _bar = iss::ext|_bar;
+  tearoff _bar = iss::ext|get#_bar;
+}
+static method ext|_bar(final iss::C* #this) → dynamic {
+  try {
+    throw "producing a stack trace";
+  }
+  on dynamic catch(final dynamic e, final core::StackTrace* s) {
+    core::print(s);
+  }
+}
+static method ext|get#_bar(final iss::C* #this) → () →* dynamic
+  return () → dynamic => iss::ext|_bar(#this);
+
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/issue38750_lib2.dart:9:5: Error: The method '_bar' isn't defined for the class 'C'.
+//  - 'C' is from 'pkg/front_end/testcases/extensions/issue38750_lib1.dart'.
+// Try correcting the name to the name of an existing method, or defining a method named '_bar'.
+//   c._bar();
+//     ^^^^
+//
+import self as self2;
+import "issue38750_lib1.dart" as iss;
+
+import "org-dartlang-testcase:///issue38750_lib1.dart";
+
+static method errors() → dynamic {
+  iss::C* c = new iss::C::•();
+  invalid-expression "pkg/front_end/testcases/extensions/issue38750_lib2.dart:9:5: Error: The method '_bar' isn't defined for the class 'C'.
+ - 'C' is from 'pkg/front_end/testcases/extensions/issue38750_lib1.dart'.
+Try correcting the name to the name of an existing method, or defining a method named '_bar'.
+  c._bar();
+    ^^^^";
+}
diff --git a/pkg/front_end/testcases/extensions/issue38750_lib1.dart b/pkg/front_end/testcases/extensions/issue38750_lib1.dart
new file mode 100644
index 0000000..e2913d7
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38750_lib1.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.
+
+class C {
+  foo() => _foo();
+  _foo() {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      print(s);
+    }
+  }
+
+  static _staticFoo() {
+    print("_staticFoo");
+  }
+
+  static staticFoo() => C._staticFoo();
+}
+
+extension ext on C {
+  _bar() {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      print(s);
+    }
+  }
+}
diff --git a/pkg/front_end/testcases/extensions/issue38750_lib2.dart b/pkg/front_end/testcases/extensions/issue38750_lib2.dart
new file mode 100644
index 0000000..8432aad
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38750_lib2.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.
+
+import 'issue38750_lib1.dart';
+
+errors() {
+  C c = new C();
+  c._bar();
+}
diff --git a/pkg/front_end/testcases/extensions/issue38755.dart b/pkg/front_end/testcases/extensions/issue38755.dart
new file mode 100644
index 0000000..cdc9cca
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38755.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.
+
+final list = ["a", "b", "c"].myMap((it) => it);
+
+extension A<T> on List<T> {
+  List<R> myMap<R>(R Function(T) block) {
+    return map(block).toList();
+  }
+}
+
+main() {
+  print(list);
+}
diff --git a/pkg/front_end/testcases/extensions/issue38755.dart.outline.expect b/pkg/front_end/testcases/extensions/issue38755.dart.outline.expect
new file mode 100644
index 0000000..f901d42
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38755.dart.outline.expect
@@ -0,0 +1,15 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+extension A<T extends core::Object* = dynamic> on core::List<T*>* {
+  method myMap = self::A|myMap;
+  tearoff myMap = self::A|get#myMap;
+}
+static final field core::List<core::String*>* list;
+static method A|myMap<T extends core::Object* = dynamic, R extends core::Object* = dynamic>(final core::List<self::A|myMap::T*>* #this, (self::A|myMap::T*) →* self::A|myMap::R* block) → core::List<self::A|myMap::R*>*
+  ;
+static method A|get#myMap<T extends core::Object* = dynamic>(final core::List<self::A|get#myMap::T*>* #this) → <R extends core::Object* = dynamic>((self::A|get#myMap::T*) →* R*) →* core::List<R*>*
+  return <R extends core::Object* = dynamic>((self::A|get#myMap::T*) →* R* block) → core::List<R*>* => self::A|myMap<self::A|get#myMap::T*, R*>(#this, block);
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/issue38755.dart.strong.expect b/pkg/front_end/testcases/extensions/issue38755.dart.strong.expect
new file mode 100644
index 0000000..31b4214
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38755.dart.strong.expect
@@ -0,0 +1,17 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+extension A<T extends core::Object* = dynamic> on core::List<T*>* {
+  method myMap = self::A|myMap;
+  tearoff myMap = self::A|get#myMap;
+}
+static final field core::List<core::String*>* list = self::A|myMap<core::String*, core::String*>(<core::String*>["a", "b", "c"], (core::String* it) → core::String* => it);
+static method A|myMap<T extends core::Object* = dynamic, R extends core::Object* = dynamic>(final core::List<self::A|myMap::T*>* #this, (self::A|myMap::T*) →* self::A|myMap::R* block) → core::List<self::A|myMap::R*>* {
+  return #this.{core::Iterable::map}<self::A|myMap::R*>(block).{core::Iterable::toList}();
+}
+static method A|get#myMap<T extends core::Object* = dynamic>(final core::List<self::A|get#myMap::T*>* #this) → <R extends core::Object* = dynamic>((self::A|get#myMap::T*) →* R*) →* core::List<R*>*
+  return <R extends core::Object* = dynamic>((self::A|get#myMap::T*) →* R* block) → core::List<R*>* => self::A|myMap<self::A|get#myMap::T*, R*>(#this, block);
+static method main() → dynamic {
+  core::print(self::list);
+}
diff --git a/pkg/front_end/testcases/extensions/issue38755.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/issue38755.dart.strong.transformed.expect
new file mode 100644
index 0000000..31b4214
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/issue38755.dart.strong.transformed.expect
@@ -0,0 +1,17 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+extension A<T extends core::Object* = dynamic> on core::List<T*>* {
+  method myMap = self::A|myMap;
+  tearoff myMap = self::A|get#myMap;
+}
+static final field core::List<core::String*>* list = self::A|myMap<core::String*, core::String*>(<core::String*>["a", "b", "c"], (core::String* it) → core::String* => it);
+static method A|myMap<T extends core::Object* = dynamic, R extends core::Object* = dynamic>(final core::List<self::A|myMap::T*>* #this, (self::A|myMap::T*) →* self::A|myMap::R* block) → core::List<self::A|myMap::R*>* {
+  return #this.{core::Iterable::map}<self::A|myMap::R*>(block).{core::Iterable::toList}();
+}
+static method A|get#myMap<T extends core::Object* = dynamic>(final core::List<self::A|get#myMap::T*>* #this) → <R extends core::Object* = dynamic>((self::A|get#myMap::T*) →* R*) →* core::List<R*>*
+  return <R extends core::Object* = dynamic>((self::A|get#myMap::T*) →* R* block) → core::List<R*>* => self::A|myMap<self::A|get#myMap::T*, R*>(#this, block);
+static method main() → dynamic {
+  core::print(self::list);
+}
diff --git a/pkg/front_end/testcases/extensions/private_members.dart b/pkg/front_end/testcases/extensions/private_members.dart
new file mode 100644
index 0000000..59b873f
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/private_members.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.
+
+import 'private_members_lib.dart';
+
+main() {
+  test();
+
+  expect(123, "".publicMethod2());
+  expect(123, PublicExtension("").publicMethod2());
+
+  expect(321, PublicExtension.publicStaticMethod2());
+}
+
+errors() {
+  expect(42, "".publicMethod1());
+  expect(87, ""._privateMethod1());
+  expect(237, ""._privateMethod2());
+  expect(473, "".publicMethod3());
+  expect(586, ""._privateMethod3());
+
+  expect(42, _PrivateExtension("").publicMethod1());
+  expect(87, _PrivateExtension("")._privateMethod1());
+  expect(237, PublicExtension("")._privateMethod2());
+
+  expect(24, _PrivateExtension.publicStaticMethod1());
+  expect(78, _PrivateExtension._privateStaticMethod1());
+  expect(732, PublicExtension._privateStaticMethod2());
+}
diff --git a/pkg/front_end/testcases/extensions/private_members.dart.outline.expect b/pkg/front_end/testcases/extensions/private_members.dart.outline.expect
new file mode 100644
index 0000000..adc6463
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/private_members.dart.outline.expect
@@ -0,0 +1,96 @@
+library;
+import self as self;
+
+import "org-dartlang-testcase:///private_members_lib.dart";
+
+static method main() → dynamic
+  ;
+static method errors() → dynamic
+  ;
+
+library;
+import self as self2;
+import "dart:core" as core;
+
+extension _PrivateExtension on core::String* {
+  method publicMethod1 = self2::_PrivateExtension|publicMethod1;
+  tearoff publicMethod1 = self2::_PrivateExtension|get#publicMethod1;
+  method _privateMethod1 = self2::_PrivateExtension|_privateMethod1;
+  tearoff _privateMethod1 = self2::_PrivateExtension|get#_privateMethod1;
+  static method publicStaticMethod1 = self2::_PrivateExtension|publicStaticMethod1;
+  static method _privateStaticMethod1 = self2::_PrivateExtension|_privateStaticMethod1;
+  method test1 = self2::_PrivateExtension|test1;
+  tearoff test1 = self2::_PrivateExtension|get#test1;
+}
+extension PublicExtension on core::String* {
+  method publicMethod2 = self2::PublicExtension|publicMethod2;
+  tearoff publicMethod2 = self2::PublicExtension|get#publicMethod2;
+  method _privateMethod2 = self2::PublicExtension|_privateMethod2;
+  tearoff _privateMethod2 = self2::PublicExtension|get#_privateMethod2;
+  static method publicStaticMethod2 = self2::PublicExtension|publicStaticMethod2;
+  static method _privateStaticMethod2 = self2::PublicExtension|_privateStaticMethod2;
+  method test2 = self2::PublicExtension|test2;
+  tearoff test2 = self2::PublicExtension|get#test2;
+}
+extension _extension#0 on core::String* {
+  method publicMethod3 = self2::_extension#0|publicMethod3;
+  tearoff publicMethod3 = self2::_extension#0|get#publicMethod3;
+  method _privateMethod3 = self2::_extension#0|_privateMethod3;
+  tearoff _privateMethod3 = self2::_extension#0|get#_privateMethod3;
+  static method publicStaticMethod3 = self2::_extension#0|publicStaticMethod3;
+  static method _privateStaticMethod3 = self2::_extension#0|_privateStaticMethod3;
+  method test3 = self2::_extension#0|test3;
+  tearoff test3 = self2::_extension#0|get#test3;
+}
+static method _PrivateExtension|publicMethod1(final core::String* #this) → core::int*
+  ;
+static method _PrivateExtension|get#publicMethod1(final core::String* #this) → () →* core::int*
+  return () → core::int* => self2::_PrivateExtension|publicMethod1(#this);
+static method _PrivateExtension|_privateMethod1(final core::String* #this) → core::int*
+  ;
+static method _PrivateExtension|get#_privateMethod1(final core::String* #this) → () →* core::int*
+  return () → core::int* => self2::_PrivateExtension|_privateMethod1(#this);
+static method _PrivateExtension|publicStaticMethod1() → core::int*
+  ;
+static method _PrivateExtension|_privateStaticMethod1() → core::int*
+  ;
+static method _PrivateExtension|test1(final core::String* #this) → dynamic
+  ;
+static method _PrivateExtension|get#test1(final core::String* #this) → () →* dynamic
+  return () → dynamic => self2::_PrivateExtension|test1(#this);
+static method PublicExtension|publicMethod2(final core::String* #this) → core::int*
+  ;
+static method PublicExtension|get#publicMethod2(final core::String* #this) → () →* core::int*
+  return () → core::int* => self2::PublicExtension|publicMethod2(#this);
+static method PublicExtension|_privateMethod2(final core::String* #this) → core::int*
+  ;
+static method PublicExtension|get#_privateMethod2(final core::String* #this) → () →* core::int*
+  return () → core::int* => self2::PublicExtension|_privateMethod2(#this);
+static method PublicExtension|publicStaticMethod2() → core::int*
+  ;
+static method PublicExtension|_privateStaticMethod2() → core::int*
+  ;
+static method PublicExtension|test2(final core::String* #this) → dynamic
+  ;
+static method PublicExtension|get#test2(final core::String* #this) → () →* dynamic
+  return () → dynamic => self2::PublicExtension|test2(#this);
+static method _extension#0|publicMethod3(final core::String* #this) → core::int*
+  ;
+static method _extension#0|get#publicMethod3(final core::String* #this) → () →* core::int*
+  return () → core::int* => self2::_extension#0|publicMethod3(#this);
+static method _extension#0|_privateMethod3(final core::String* #this) → core::int*
+  ;
+static method _extension#0|get#_privateMethod3(final core::String* #this) → () →* core::int*
+  return () → core::int* => self2::_extension#0|_privateMethod3(#this);
+static method _extension#0|publicStaticMethod3() → core::int*
+  ;
+static method _extension#0|_privateStaticMethod3() → core::int*
+  ;
+static method _extension#0|test3(final core::String* #this) → dynamic
+  ;
+static method _extension#0|get#test3(final core::String* #this) → () →* dynamic
+  return () → dynamic => self2::_extension#0|test3(#this);
+static method test() → dynamic
+  ;
+static method expect(dynamic expected, dynamic actual) → dynamic
+  ;
diff --git a/pkg/front_end/testcases/extensions/private_members.dart.strong.expect b/pkg/front_end/testcases/extensions/private_members.dart.strong.expect
new file mode 100644
index 0000000..79b67f0
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/private_members.dart.strong.expect
@@ -0,0 +1,223 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/private_members.dart:23:14: Error: Method not found: '_PrivateExtension'.
+//   expect(42, _PrivateExtension("").publicMethod1());
+//              ^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/private_members.dart:24:14: Error: Method not found: '_PrivateExtension'.
+//   expect(87, _PrivateExtension("")._privateMethod1());
+//              ^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/private_members.dart:25:35: Error: Method not found: '_privateMethod2'.
+//   expect(237, PublicExtension("")._privateMethod2());
+//                                   ^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/private_members.dart:27:14: Error: Getter not found: '_PrivateExtension'.
+//   expect(24, _PrivateExtension.publicStaticMethod1());
+//              ^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/private_members.dart:28:14: Error: Getter not found: '_PrivateExtension'.
+//   expect(78, _PrivateExtension._privateStaticMethod1());
+//              ^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/private_members.dart:29:31: Error: Method not found: 'PublicExtension._privateStaticMethod2'.
+//   expect(732, PublicExtension._privateStaticMethod2());
+//                               ^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/private_members.dart:17:17: Error: The method 'publicMethod1' isn't defined for the class 'String'.
+// Try correcting the name to the name of an existing method, or defining a method named 'publicMethod1'.
+//   expect(42, "".publicMethod1());
+//                 ^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/private_members.dart:18:17: Error: The method '_privateMethod1' isn't defined for the class 'String'.
+// Try correcting the name to the name of an existing method, or defining a method named '_privateMethod1'.
+//   expect(87, ""._privateMethod1());
+//                 ^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/private_members.dart:19:18: Error: The method '_privateMethod2' isn't defined for the class 'String'.
+// Try correcting the name to the name of an existing method, or defining a method named '_privateMethod2'.
+//   expect(237, ""._privateMethod2());
+//                  ^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/private_members.dart:20:18: Error: The method 'publicMethod3' isn't defined for the class 'String'.
+// Try correcting the name to the name of an existing method, or defining a method named 'publicMethod3'.
+//   expect(473, "".publicMethod3());
+//                  ^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/private_members.dart:21:18: Error: The method '_privateMethod3' isn't defined for the class 'String'.
+// Try correcting the name to the name of an existing method, or defining a method named '_privateMethod3'.
+//   expect(586, ""._privateMethod3());
+//                  ^^^^^^^^^^^^^^^
+//
+import self as self;
+import "private_members_lib.dart" as pri;
+
+import "org-dartlang-testcase:///private_members_lib.dart";
+
+static method main() → dynamic {
+  pri::test();
+  pri::expect(123, pri::PublicExtension|publicMethod2(""));
+  pri::expect(123, pri::PublicExtension|publicMethod2(""));
+  pri::expect(321, pri::PublicExtension|publicStaticMethod2());
+}
+static method errors() → dynamic {
+  pri::expect(42, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:17:17: Error: The method 'publicMethod1' isn't defined for the class 'String'.
+Try correcting the name to the name of an existing method, or defining a method named 'publicMethod1'.
+  expect(42, \"\".publicMethod1());
+                ^^^^^^^^^^^^^");
+  pri::expect(87, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:18:17: Error: The method '_privateMethod1' isn't defined for the class 'String'.
+Try correcting the name to the name of an existing method, or defining a method named '_privateMethod1'.
+  expect(87, \"\"._privateMethod1());
+                ^^^^^^^^^^^^^^^");
+  pri::expect(237, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:19:18: Error: The method '_privateMethod2' isn't defined for the class 'String'.
+Try correcting the name to the name of an existing method, or defining a method named '_privateMethod2'.
+  expect(237, \"\"._privateMethod2());
+                 ^^^^^^^^^^^^^^^");
+  pri::expect(473, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:20:18: Error: The method 'publicMethod3' isn't defined for the class 'String'.
+Try correcting the name to the name of an existing method, or defining a method named 'publicMethod3'.
+  expect(473, \"\".publicMethod3());
+                 ^^^^^^^^^^^^^");
+  pri::expect(586, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:21:18: Error: The method '_privateMethod3' isn't defined for the class 'String'.
+Try correcting the name to the name of an existing method, or defining a method named '_privateMethod3'.
+  expect(586, \"\"._privateMethod3());
+                 ^^^^^^^^^^^^^^^");
+  pri::expect(42, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:23:14: Error: Method not found: '_PrivateExtension'.
+  expect(42, _PrivateExtension(\"\").publicMethod1());
+             ^^^^^^^^^^^^^^^^^".publicMethod1());
+  pri::expect(87, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:24:14: Error: Method not found: '_PrivateExtension'.
+  expect(87, _PrivateExtension(\"\")._privateMethod1());
+             ^^^^^^^^^^^^^^^^^"._privateMethod1());
+  pri::expect(237, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:25:35: Error: Method not found: '_privateMethod2'.
+  expect(237, PublicExtension(\"\")._privateMethod2());
+                                  ^^^^^^^^^^^^^^^");
+  pri::expect(24, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:27:14: Error: Getter not found: '_PrivateExtension'.
+  expect(24, _PrivateExtension.publicStaticMethod1());
+             ^^^^^^^^^^^^^^^^^".publicStaticMethod1());
+  pri::expect(78, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:28:14: Error: Getter not found: '_PrivateExtension'.
+  expect(78, _PrivateExtension._privateStaticMethod1());
+             ^^^^^^^^^^^^^^^^^"._privateStaticMethod1());
+  pri::expect(732, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:29:31: Error: Method not found: 'PublicExtension._privateStaticMethod2'.
+  expect(732, PublicExtension._privateStaticMethod2());
+                              ^^^^^^^^^^^^^^^^^^^^^");
+}
+
+library;
+import self as pri;
+import "dart:core" as core;
+
+extension _PrivateExtension on core::String* {
+  method publicMethod1 = pri::_PrivateExtension|publicMethod1;
+  tearoff publicMethod1 = pri::_PrivateExtension|get#publicMethod1;
+  method _privateMethod1 = pri::_PrivateExtension|_privateMethod1;
+  tearoff _privateMethod1 = pri::_PrivateExtension|get#_privateMethod1;
+  static method publicStaticMethod1 = pri::_PrivateExtension|publicStaticMethod1;
+  static method _privateStaticMethod1 = pri::_PrivateExtension|_privateStaticMethod1;
+  method test1 = pri::_PrivateExtension|test1;
+  tearoff test1 = pri::_PrivateExtension|get#test1;
+}
+extension PublicExtension on core::String* {
+  method publicMethod2 = pri::PublicExtension|publicMethod2;
+  tearoff publicMethod2 = pri::PublicExtension|get#publicMethod2;
+  method _privateMethod2 = pri::PublicExtension|_privateMethod2;
+  tearoff _privateMethod2 = pri::PublicExtension|get#_privateMethod2;
+  static method publicStaticMethod2 = pri::PublicExtension|publicStaticMethod2;
+  static method _privateStaticMethod2 = pri::PublicExtension|_privateStaticMethod2;
+  method test2 = pri::PublicExtension|test2;
+  tearoff test2 = pri::PublicExtension|get#test2;
+}
+extension _extension#0 on core::String* {
+  method publicMethod3 = pri::_extension#0|publicMethod3;
+  tearoff publicMethod3 = pri::_extension#0|get#publicMethod3;
+  method _privateMethod3 = pri::_extension#0|_privateMethod3;
+  tearoff _privateMethod3 = pri::_extension#0|get#_privateMethod3;
+  static method publicStaticMethod3 = pri::_extension#0|publicStaticMethod3;
+  static method _privateStaticMethod3 = pri::_extension#0|_privateStaticMethod3;
+  method test3 = pri::_extension#0|test3;
+  tearoff test3 = pri::_extension#0|get#test3;
+}
+static method _PrivateExtension|publicMethod1(final core::String* #this) → core::int*
+  return 42;
+static method _PrivateExtension|get#publicMethod1(final core::String* #this) → () →* core::int*
+  return () → core::int* => pri::_PrivateExtension|publicMethod1(#this);
+static method _PrivateExtension|_privateMethod1(final core::String* #this) → core::int*
+  return 87;
+static method _PrivateExtension|get#_privateMethod1(final core::String* #this) → () →* core::int*
+  return () → core::int* => pri::_PrivateExtension|_privateMethod1(#this);
+static method _PrivateExtension|publicStaticMethod1() → core::int*
+  return 24;
+static method _PrivateExtension|_privateStaticMethod1() → core::int*
+  return 78;
+static method _PrivateExtension|test1(final core::String* #this) → dynamic {
+  pri::expect(42, pri::_PrivateExtension|publicMethod1(#this));
+  pri::expect(87, pri::_PrivateExtension|_privateMethod1(#this));
+  pri::expect(24, pri::_PrivateExtension|publicStaticMethod1());
+  pri::expect(78, pri::_PrivateExtension|_privateStaticMethod1());
+}
+static method _PrivateExtension|get#test1(final core::String* #this) → () →* dynamic
+  return () → dynamic => pri::_PrivateExtension|test1(#this);
+static method PublicExtension|publicMethod2(final core::String* #this) → core::int*
+  return 123;
+static method PublicExtension|get#publicMethod2(final core::String* #this) → () →* core::int*
+  return () → core::int* => pri::PublicExtension|publicMethod2(#this);
+static method PublicExtension|_privateMethod2(final core::String* #this) → core::int*
+  return 237;
+static method PublicExtension|get#_privateMethod2(final core::String* #this) → () →* core::int*
+  return () → core::int* => pri::PublicExtension|_privateMethod2(#this);
+static method PublicExtension|publicStaticMethod2() → core::int*
+  return 321;
+static method PublicExtension|_privateStaticMethod2() → core::int*
+  return 732;
+static method PublicExtension|test2(final core::String* #this) → dynamic {
+  pri::expect(123, pri::PublicExtension|publicMethod2(#this));
+  pri::expect(237, pri::PublicExtension|_privateMethod2(#this));
+  pri::expect(321, pri::PublicExtension|publicStaticMethod2());
+  pri::expect(732, pri::PublicExtension|_privateStaticMethod2());
+}
+static method PublicExtension|get#test2(final core::String* #this) → () →* dynamic
+  return () → dynamic => pri::PublicExtension|test2(#this);
+static method _extension#0|publicMethod3(final core::String* #this) → core::int*
+  return 473;
+static method _extension#0|get#publicMethod3(final core::String* #this) → () →* core::int*
+  return () → core::int* => pri::_extension#0|publicMethod3(#this);
+static method _extension#0|_privateMethod3(final core::String* #this) → core::int*
+  return 586;
+static method _extension#0|get#_privateMethod3(final core::String* #this) → () →* core::int*
+  return () → core::int* => pri::_extension#0|_privateMethod3(#this);
+static method _extension#0|publicStaticMethod3() → core::int*
+  return 374;
+static method _extension#0|_privateStaticMethod3() → core::int*
+  return 685;
+static method _extension#0|test3(final core::String* #this) → dynamic {
+  pri::expect(473, pri::_extension#0|publicMethod3(#this));
+  pri::expect(586, pri::_extension#0|_privateMethod3(#this));
+  pri::expect(374, pri::_extension#0|publicStaticMethod3());
+  pri::expect(685, pri::_extension#0|_privateStaticMethod3());
+}
+static method _extension#0|get#test3(final core::String* #this) → () →* dynamic
+  return () → dynamic => pri::_extension#0|test3(#this);
+static method test() → dynamic {
+  pri::expect(42, pri::_PrivateExtension|publicMethod1(""));
+  pri::expect(87, pri::_PrivateExtension|_privateMethod1(""));
+  pri::expect(123, pri::PublicExtension|publicMethod2(""));
+  pri::expect(237, pri::PublicExtension|_privateMethod2(""));
+  pri::expect(473, pri::_extension#0|publicMethod3(""));
+  pri::expect(586, pri::_extension#0|_privateMethod3(""));
+  pri::expect(42, pri::_PrivateExtension|publicMethod1(""));
+  pri::expect(87, pri::_PrivateExtension|_privateMethod1(""));
+  pri::expect(123, pri::PublicExtension|publicMethod2(""));
+  pri::expect(237, pri::PublicExtension|_privateMethod2(""));
+  pri::expect(24, pri::_PrivateExtension|publicStaticMethod1());
+  pri::expect(78, pri::_PrivateExtension|_privateStaticMethod1());
+  pri::expect(321, pri::PublicExtension|publicStaticMethod2());
+  pri::expect(732, pri::PublicExtension|_privateStaticMethod2());
+  pri::_PrivateExtension|test1("");
+  pri::PublicExtension|test2("");
+  pri::_extension#0|test3("");
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual)) {
+    throw "Mismatch: expected=${expected}, actual=${actual}";
+  }
+}
diff --git a/pkg/front_end/testcases/extensions/private_members.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/private_members.dart.strong.transformed.expect
new file mode 100644
index 0000000..79b67f0
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/private_members.dart.strong.transformed.expect
@@ -0,0 +1,223 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/extensions/private_members.dart:23:14: Error: Method not found: '_PrivateExtension'.
+//   expect(42, _PrivateExtension("").publicMethod1());
+//              ^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/private_members.dart:24:14: Error: Method not found: '_PrivateExtension'.
+//   expect(87, _PrivateExtension("")._privateMethod1());
+//              ^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/private_members.dart:25:35: Error: Method not found: '_privateMethod2'.
+//   expect(237, PublicExtension("")._privateMethod2());
+//                                   ^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/private_members.dart:27:14: Error: Getter not found: '_PrivateExtension'.
+//   expect(24, _PrivateExtension.publicStaticMethod1());
+//              ^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/private_members.dart:28:14: Error: Getter not found: '_PrivateExtension'.
+//   expect(78, _PrivateExtension._privateStaticMethod1());
+//              ^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/private_members.dart:29:31: Error: Method not found: 'PublicExtension._privateStaticMethod2'.
+//   expect(732, PublicExtension._privateStaticMethod2());
+//                               ^^^^^^^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/private_members.dart:17:17: Error: The method 'publicMethod1' isn't defined for the class 'String'.
+// Try correcting the name to the name of an existing method, or defining a method named 'publicMethod1'.
+//   expect(42, "".publicMethod1());
+//                 ^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/private_members.dart:18:17: Error: The method '_privateMethod1' isn't defined for the class 'String'.
+// Try correcting the name to the name of an existing method, or defining a method named '_privateMethod1'.
+//   expect(87, ""._privateMethod1());
+//                 ^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/private_members.dart:19:18: Error: The method '_privateMethod2' isn't defined for the class 'String'.
+// Try correcting the name to the name of an existing method, or defining a method named '_privateMethod2'.
+//   expect(237, ""._privateMethod2());
+//                  ^^^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/private_members.dart:20:18: Error: The method 'publicMethod3' isn't defined for the class 'String'.
+// Try correcting the name to the name of an existing method, or defining a method named 'publicMethod3'.
+//   expect(473, "".publicMethod3());
+//                  ^^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/extensions/private_members.dart:21:18: Error: The method '_privateMethod3' isn't defined for the class 'String'.
+// Try correcting the name to the name of an existing method, or defining a method named '_privateMethod3'.
+//   expect(586, ""._privateMethod3());
+//                  ^^^^^^^^^^^^^^^
+//
+import self as self;
+import "private_members_lib.dart" as pri;
+
+import "org-dartlang-testcase:///private_members_lib.dart";
+
+static method main() → dynamic {
+  pri::test();
+  pri::expect(123, pri::PublicExtension|publicMethod2(""));
+  pri::expect(123, pri::PublicExtension|publicMethod2(""));
+  pri::expect(321, pri::PublicExtension|publicStaticMethod2());
+}
+static method errors() → dynamic {
+  pri::expect(42, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:17:17: Error: The method 'publicMethod1' isn't defined for the class 'String'.
+Try correcting the name to the name of an existing method, or defining a method named 'publicMethod1'.
+  expect(42, \"\".publicMethod1());
+                ^^^^^^^^^^^^^");
+  pri::expect(87, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:18:17: Error: The method '_privateMethod1' isn't defined for the class 'String'.
+Try correcting the name to the name of an existing method, or defining a method named '_privateMethod1'.
+  expect(87, \"\"._privateMethod1());
+                ^^^^^^^^^^^^^^^");
+  pri::expect(237, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:19:18: Error: The method '_privateMethod2' isn't defined for the class 'String'.
+Try correcting the name to the name of an existing method, or defining a method named '_privateMethod2'.
+  expect(237, \"\"._privateMethod2());
+                 ^^^^^^^^^^^^^^^");
+  pri::expect(473, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:20:18: Error: The method 'publicMethod3' isn't defined for the class 'String'.
+Try correcting the name to the name of an existing method, or defining a method named 'publicMethod3'.
+  expect(473, \"\".publicMethod3());
+                 ^^^^^^^^^^^^^");
+  pri::expect(586, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:21:18: Error: The method '_privateMethod3' isn't defined for the class 'String'.
+Try correcting the name to the name of an existing method, or defining a method named '_privateMethod3'.
+  expect(586, \"\"._privateMethod3());
+                 ^^^^^^^^^^^^^^^");
+  pri::expect(42, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:23:14: Error: Method not found: '_PrivateExtension'.
+  expect(42, _PrivateExtension(\"\").publicMethod1());
+             ^^^^^^^^^^^^^^^^^".publicMethod1());
+  pri::expect(87, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:24:14: Error: Method not found: '_PrivateExtension'.
+  expect(87, _PrivateExtension(\"\")._privateMethod1());
+             ^^^^^^^^^^^^^^^^^"._privateMethod1());
+  pri::expect(237, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:25:35: Error: Method not found: '_privateMethod2'.
+  expect(237, PublicExtension(\"\")._privateMethod2());
+                                  ^^^^^^^^^^^^^^^");
+  pri::expect(24, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:27:14: Error: Getter not found: '_PrivateExtension'.
+  expect(24, _PrivateExtension.publicStaticMethod1());
+             ^^^^^^^^^^^^^^^^^".publicStaticMethod1());
+  pri::expect(78, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:28:14: Error: Getter not found: '_PrivateExtension'.
+  expect(78, _PrivateExtension._privateStaticMethod1());
+             ^^^^^^^^^^^^^^^^^"._privateStaticMethod1());
+  pri::expect(732, invalid-expression "pkg/front_end/testcases/extensions/private_members.dart:29:31: Error: Method not found: 'PublicExtension._privateStaticMethod2'.
+  expect(732, PublicExtension._privateStaticMethod2());
+                              ^^^^^^^^^^^^^^^^^^^^^");
+}
+
+library;
+import self as pri;
+import "dart:core" as core;
+
+extension _PrivateExtension on core::String* {
+  method publicMethod1 = pri::_PrivateExtension|publicMethod1;
+  tearoff publicMethod1 = pri::_PrivateExtension|get#publicMethod1;
+  method _privateMethod1 = pri::_PrivateExtension|_privateMethod1;
+  tearoff _privateMethod1 = pri::_PrivateExtension|get#_privateMethod1;
+  static method publicStaticMethod1 = pri::_PrivateExtension|publicStaticMethod1;
+  static method _privateStaticMethod1 = pri::_PrivateExtension|_privateStaticMethod1;
+  method test1 = pri::_PrivateExtension|test1;
+  tearoff test1 = pri::_PrivateExtension|get#test1;
+}
+extension PublicExtension on core::String* {
+  method publicMethod2 = pri::PublicExtension|publicMethod2;
+  tearoff publicMethod2 = pri::PublicExtension|get#publicMethod2;
+  method _privateMethod2 = pri::PublicExtension|_privateMethod2;
+  tearoff _privateMethod2 = pri::PublicExtension|get#_privateMethod2;
+  static method publicStaticMethod2 = pri::PublicExtension|publicStaticMethod2;
+  static method _privateStaticMethod2 = pri::PublicExtension|_privateStaticMethod2;
+  method test2 = pri::PublicExtension|test2;
+  tearoff test2 = pri::PublicExtension|get#test2;
+}
+extension _extension#0 on core::String* {
+  method publicMethod3 = pri::_extension#0|publicMethod3;
+  tearoff publicMethod3 = pri::_extension#0|get#publicMethod3;
+  method _privateMethod3 = pri::_extension#0|_privateMethod3;
+  tearoff _privateMethod3 = pri::_extension#0|get#_privateMethod3;
+  static method publicStaticMethod3 = pri::_extension#0|publicStaticMethod3;
+  static method _privateStaticMethod3 = pri::_extension#0|_privateStaticMethod3;
+  method test3 = pri::_extension#0|test3;
+  tearoff test3 = pri::_extension#0|get#test3;
+}
+static method _PrivateExtension|publicMethod1(final core::String* #this) → core::int*
+  return 42;
+static method _PrivateExtension|get#publicMethod1(final core::String* #this) → () →* core::int*
+  return () → core::int* => pri::_PrivateExtension|publicMethod1(#this);
+static method _PrivateExtension|_privateMethod1(final core::String* #this) → core::int*
+  return 87;
+static method _PrivateExtension|get#_privateMethod1(final core::String* #this) → () →* core::int*
+  return () → core::int* => pri::_PrivateExtension|_privateMethod1(#this);
+static method _PrivateExtension|publicStaticMethod1() → core::int*
+  return 24;
+static method _PrivateExtension|_privateStaticMethod1() → core::int*
+  return 78;
+static method _PrivateExtension|test1(final core::String* #this) → dynamic {
+  pri::expect(42, pri::_PrivateExtension|publicMethod1(#this));
+  pri::expect(87, pri::_PrivateExtension|_privateMethod1(#this));
+  pri::expect(24, pri::_PrivateExtension|publicStaticMethod1());
+  pri::expect(78, pri::_PrivateExtension|_privateStaticMethod1());
+}
+static method _PrivateExtension|get#test1(final core::String* #this) → () →* dynamic
+  return () → dynamic => pri::_PrivateExtension|test1(#this);
+static method PublicExtension|publicMethod2(final core::String* #this) → core::int*
+  return 123;
+static method PublicExtension|get#publicMethod2(final core::String* #this) → () →* core::int*
+  return () → core::int* => pri::PublicExtension|publicMethod2(#this);
+static method PublicExtension|_privateMethod2(final core::String* #this) → core::int*
+  return 237;
+static method PublicExtension|get#_privateMethod2(final core::String* #this) → () →* core::int*
+  return () → core::int* => pri::PublicExtension|_privateMethod2(#this);
+static method PublicExtension|publicStaticMethod2() → core::int*
+  return 321;
+static method PublicExtension|_privateStaticMethod2() → core::int*
+  return 732;
+static method PublicExtension|test2(final core::String* #this) → dynamic {
+  pri::expect(123, pri::PublicExtension|publicMethod2(#this));
+  pri::expect(237, pri::PublicExtension|_privateMethod2(#this));
+  pri::expect(321, pri::PublicExtension|publicStaticMethod2());
+  pri::expect(732, pri::PublicExtension|_privateStaticMethod2());
+}
+static method PublicExtension|get#test2(final core::String* #this) → () →* dynamic
+  return () → dynamic => pri::PublicExtension|test2(#this);
+static method _extension#0|publicMethod3(final core::String* #this) → core::int*
+  return 473;
+static method _extension#0|get#publicMethod3(final core::String* #this) → () →* core::int*
+  return () → core::int* => pri::_extension#0|publicMethod3(#this);
+static method _extension#0|_privateMethod3(final core::String* #this) → core::int*
+  return 586;
+static method _extension#0|get#_privateMethod3(final core::String* #this) → () →* core::int*
+  return () → core::int* => pri::_extension#0|_privateMethod3(#this);
+static method _extension#0|publicStaticMethod3() → core::int*
+  return 374;
+static method _extension#0|_privateStaticMethod3() → core::int*
+  return 685;
+static method _extension#0|test3(final core::String* #this) → dynamic {
+  pri::expect(473, pri::_extension#0|publicMethod3(#this));
+  pri::expect(586, pri::_extension#0|_privateMethod3(#this));
+  pri::expect(374, pri::_extension#0|publicStaticMethod3());
+  pri::expect(685, pri::_extension#0|_privateStaticMethod3());
+}
+static method _extension#0|get#test3(final core::String* #this) → () →* dynamic
+  return () → dynamic => pri::_extension#0|test3(#this);
+static method test() → dynamic {
+  pri::expect(42, pri::_PrivateExtension|publicMethod1(""));
+  pri::expect(87, pri::_PrivateExtension|_privateMethod1(""));
+  pri::expect(123, pri::PublicExtension|publicMethod2(""));
+  pri::expect(237, pri::PublicExtension|_privateMethod2(""));
+  pri::expect(473, pri::_extension#0|publicMethod3(""));
+  pri::expect(586, pri::_extension#0|_privateMethod3(""));
+  pri::expect(42, pri::_PrivateExtension|publicMethod1(""));
+  pri::expect(87, pri::_PrivateExtension|_privateMethod1(""));
+  pri::expect(123, pri::PublicExtension|publicMethod2(""));
+  pri::expect(237, pri::PublicExtension|_privateMethod2(""));
+  pri::expect(24, pri::_PrivateExtension|publicStaticMethod1());
+  pri::expect(78, pri::_PrivateExtension|_privateStaticMethod1());
+  pri::expect(321, pri::PublicExtension|publicStaticMethod2());
+  pri::expect(732, pri::PublicExtension|_privateStaticMethod2());
+  pri::_PrivateExtension|test1("");
+  pri::PublicExtension|test2("");
+  pri::_extension#0|test3("");
+}
+static method expect(dynamic expected, dynamic actual) → dynamic {
+  if(!expected.{core::Object::==}(actual)) {
+    throw "Mismatch: expected=${expected}, actual=${actual}";
+  }
+}
diff --git a/pkg/front_end/testcases/extensions/private_members_lib.dart b/pkg/front_end/testcases/extensions/private_members_lib.dart
new file mode 100644
index 0000000..2cf5032
--- /dev/null
+++ b/pkg/front_end/testcases/extensions/private_members_lib.dart
@@ -0,0 +1,74 @@
+// 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.
+
+extension _PrivateExtension on String {
+  int publicMethod1() => 42;
+  int _privateMethod1() => 87;
+  static int publicStaticMethod1() => 24;
+  static int _privateStaticMethod1() => 78;
+
+  test1() {
+    expect(42, publicMethod1());
+    expect(87, _privateMethod1());
+    expect(24, publicStaticMethod1());
+    expect(78, _privateStaticMethod1());
+  }
+}
+
+extension PublicExtension on String {
+  int publicMethod2() => 123;
+  int _privateMethod2() => 237;
+  static int publicStaticMethod2() => 321;
+  static int _privateStaticMethod2() => 732;
+
+  test2() {
+    expect(123, publicMethod2());
+    expect(237, _privateMethod2());
+    expect(321, publicStaticMethod2());
+    expect(732, _privateStaticMethod2());
+  }
+}
+
+extension on String {
+  int publicMethod3() => 473;
+  int _privateMethod3() => 586;
+  static int publicStaticMethod3() => 374;
+  static int _privateStaticMethod3() => 685;
+
+  test3() {
+    expect(473, publicMethod3());
+    expect(586, _privateMethod3());
+    expect(374, publicStaticMethod3());
+    expect(685, _privateStaticMethod3());
+  }
+}
+
+test() {
+  expect(42, "".publicMethod1());
+  expect(87, ""._privateMethod1());
+  expect(123, "".publicMethod2());
+  expect(237, ""._privateMethod2());
+  expect(473, "".publicMethod3());
+  expect(586, ""._privateMethod3());
+
+  expect(42, _PrivateExtension("").publicMethod1());
+  expect(87, _PrivateExtension("")._privateMethod1());
+  expect(123, PublicExtension("").publicMethod2());
+  expect(237, PublicExtension("")._privateMethod2());
+
+  expect(24, _PrivateExtension.publicStaticMethod1());
+  expect(78, _PrivateExtension._privateStaticMethod1());
+  expect(321, PublicExtension.publicStaticMethod2());
+  expect(732, PublicExtension._privateStaticMethod2());
+
+  "".test1();
+  "".test2();
+  "".test3();
+}
+
+expect(expected, actual) {
+  if (expected != actual) {
+    throw 'Mismatch: expected=$expected, actual=$actual';
+  }
+}
diff --git a/pkg/front_end/testcases/general/candidate_found.dart b/pkg/front_end/testcases/general/candidate_found.dart
new file mode 100644
index 0000000..6b4c624
--- /dev/null
+++ b/pkg/front_end/testcases/general/candidate_found.dart
@@ -0,0 +1,24 @@
+// 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 Fisk {
+  Fisk(int x) {}
+
+  Fisk.named(int x) {}
+
+  void method(int x) {}
+
+  static void staticMethod(int x) {}
+}
+
+test() {
+  new Fisk();
+  new Fisk.named();
+  Fisk();
+  Fisk.named();
+  Fisk.staticMethod();
+  (null as Fisk).method();
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/candidate_found.dart.outline.expect b/pkg/front_end/testcases/general/candidate_found.dart.outline.expect
new file mode 100644
index 0000000..5378db0
--- /dev/null
+++ b/pkg/front_end/testcases/general/candidate_found.dart.outline.expect
@@ -0,0 +1,18 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Fisk extends core::Object {
+  constructor •(core::int* x) → self::Fisk*
+    ;
+  constructor named(core::int* x) → self::Fisk*
+    ;
+  method method(core::int* x) → void
+    ;
+  static method staticMethod(core::int* x) → void
+    ;
+}
+static method test() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/candidate_found.dart.strong.expect b/pkg/front_end/testcases/general/candidate_found.dart.strong.expect
new file mode 100644
index 0000000..a111562
--- /dev/null
+++ b/pkg/front_end/testcases/general/candidate_found.dart.strong.expect
@@ -0,0 +1,73 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/candidate_found.dart:16:11: Error: Too few positional arguments: 1 required, 0 given.
+//   new Fisk();
+//           ^
+// pkg/front_end/testcases/general/candidate_found.dart:6:3: Context: Found this candidate, but the arguments don't match.
+//   Fisk(int x) {}
+//   ^^^^
+//
+// pkg/front_end/testcases/general/candidate_found.dart:17:17: Error: Too few positional arguments: 1 required, 0 given.
+//   new Fisk.named();
+//                 ^
+// pkg/front_end/testcases/general/candidate_found.dart:8:3: Context: Found this candidate, but the arguments don't match.
+//   Fisk.named(int x) {}
+//   ^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/candidate_found.dart:18:7: Error: Too few positional arguments: 1 required, 0 given.
+//   Fisk();
+//       ^
+// pkg/front_end/testcases/general/candidate_found.dart:6:3: Context: Found this candidate, but the arguments don't match.
+//   Fisk(int x) {}
+//   ^^^^
+//
+// pkg/front_end/testcases/general/candidate_found.dart:19:13: Error: Too few positional arguments: 1 required, 0 given.
+//   Fisk.named();
+//             ^
+// pkg/front_end/testcases/general/candidate_found.dart:8:3: Context: Found this candidate, but the arguments don't match.
+//   Fisk.named(int x) {}
+//   ^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/candidate_found.dart:20:20: Error: Too few positional arguments: 1 required, 0 given.
+//   Fisk.staticMethod();
+//                    ^
+// pkg/front_end/testcases/general/candidate_found.dart:12:15: Context: Found this candidate, but the arguments don't match.
+//   static void staticMethod(int x) {}
+//               ^^^^^^^^^^^^
+//
+// pkg/front_end/testcases/general/candidate_found.dart:21:24: Error: Too few positional arguments: 1 required, 0 given.
+//   (null as Fisk).method();
+//                        ^
+//
+import self as self;
+import "dart:core" as core;
+
+class Fisk extends core::Object {
+  constructor •(core::int* x) → self::Fisk*
+    : super core::Object::•() {}
+  constructor named(core::int* x) → self::Fisk*
+    : super core::Object::•() {}
+  method method(core::int* x) → void {}
+  static method staticMethod(core::int* x) → void {}
+}
+static method test() → dynamic {
+  invalid-expression "pkg/front_end/testcases/general/candidate_found.dart:16:11: Error: Too few positional arguments: 1 required, 0 given.
+  new Fisk();
+          ^";
+  invalid-expression "pkg/front_end/testcases/general/candidate_found.dart:17:17: Error: Too few positional arguments: 1 required, 0 given.
+  new Fisk.named();
+                ^";
+  invalid-expression "pkg/front_end/testcases/general/candidate_found.dart:18:7: Error: Too few positional arguments: 1 required, 0 given.
+  Fisk();
+      ^";
+  invalid-expression "pkg/front_end/testcases/general/candidate_found.dart:19:13: Error: Too few positional arguments: 1 required, 0 given.
+  Fisk.named();
+            ^";
+  invalid-expression "pkg/front_end/testcases/general/candidate_found.dart:20:20: Error: Too few positional arguments: 1 required, 0 given.
+  Fisk.staticMethod();
+                   ^";
+  (null as self::Fisk*).{self::Fisk::method}();
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/const_redirect_to_nonconst.dart b/pkg/front_end/testcases/general/const_redirect_to_nonconst.dart
new file mode 100644
index 0000000..3549030
--- /dev/null
+++ b/pkg/front_end/testcases/general/const_redirect_to_nonconst.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.
+
+class A {
+  const A() : this.bad();
+
+  A.bad() {}
+}
+
+class B extends A {
+  const B() : super.bad();
+}
+
+test() {
+  print(const A());
+  print(const B());
+}
+
+main() {
+  print(new A());
+  print(new B());
+}
diff --git a/pkg/front_end/testcases/general/const_redirect_to_nonconst.dart.outline.expect b/pkg/front_end/testcases/general/const_redirect_to_nonconst.dart.outline.expect
new file mode 100644
index 0000000..fdcd4b7
--- /dev/null
+++ b/pkg/front_end/testcases/general/const_redirect_to_nonconst.dart.outline.expect
@@ -0,0 +1,27 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/const_redirect_to_nonconst.dart:12:21: Error: A constant constructor can't call a non-constant super constructor.
+//   const B() : super.bad();
+//                     ^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  const constructor •() → self::A*
+    : this self::A::bad()
+    ;
+  constructor bad() → self::A*
+    ;
+}
+class B extends self::A {
+  const constructor •() → self::B*
+    : super self::A::bad()
+    ;
+}
+static method test() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/const_redirect_to_nonconst.dart.strong.expect b/pkg/front_end/testcases/general/const_redirect_to_nonconst.dart.strong.expect
new file mode 100644
index 0000000..3022157
--- /dev/null
+++ b/pkg/front_end/testcases/general/const_redirect_to_nonconst.dart.strong.expect
@@ -0,0 +1,35 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/const_redirect_to_nonconst.dart:12:21: Error: A constant constructor can't call a non-constant super constructor.
+//   const B() : super.bad();
+//                     ^^^
+//
+// pkg/front_end/testcases/general/const_redirect_to_nonconst.dart:6:20: Error: A constant constructor can't call a non-constant constructor.
+//   const A() : this.bad();
+//                    ^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  const constructor •() → self::A*
+    : this self::A::bad()
+    ;
+  constructor bad() → self::A*
+    : super core::Object::•() {}
+}
+class B extends self::A {
+  const constructor •() → self::B*
+    : super self::A::bad()
+    ;
+}
+static method test() → dynamic {
+  core::print(invalid-expression "Non-const constructor invocation.");
+  core::print(invalid-expression "Non-const constructor invocation.");
+}
+static method main() → dynamic {
+  core::print(new self::A::•());
+  core::print(new self::B::•());
+}
diff --git a/pkg/front_end/testcases/general/const_redirect_to_nonconst.dart.strong.transformed.expect b/pkg/front_end/testcases/general/const_redirect_to_nonconst.dart.strong.transformed.expect
new file mode 100644
index 0000000..3022157
--- /dev/null
+++ b/pkg/front_end/testcases/general/const_redirect_to_nonconst.dart.strong.transformed.expect
@@ -0,0 +1,35 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/general/const_redirect_to_nonconst.dart:12:21: Error: A constant constructor can't call a non-constant super constructor.
+//   const B() : super.bad();
+//                     ^^^
+//
+// pkg/front_end/testcases/general/const_redirect_to_nonconst.dart:6:20: Error: A constant constructor can't call a non-constant constructor.
+//   const A() : this.bad();
+//                    ^^^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  const constructor •() → self::A*
+    : this self::A::bad()
+    ;
+  constructor bad() → self::A*
+    : super core::Object::•() {}
+}
+class B extends self::A {
+  const constructor •() → self::B*
+    : super self::A::bad()
+    ;
+}
+static method test() → dynamic {
+  core::print(invalid-expression "Non-const constructor invocation.");
+  core::print(invalid-expression "Non-const constructor invocation.");
+}
+static method main() → dynamic {
+  core::print(new self::A::•());
+  core::print(new self::B::•());
+}
diff --git a/pkg/front_end/testcases/general/constructor_const_inference.dart.strong.expect b/pkg/front_end/testcases/general/constructor_const_inference.dart.strong.expect
index 45d397e..c95b9b2 100644
--- a/pkg/front_end/testcases/general/constructor_const_inference.dart.strong.expect
+++ b/pkg/front_end/testcases/general/constructor_const_inference.dart.strong.expect
@@ -20,7 +20,7 @@
 }
 static method main() → dynamic {
   dynamic x = new self::B::•<dynamic>().{self::A::x};
-  if(!(x is self::_Y<core::Null*>*)) {
+  if(!(x is self::_Y<core::Null?>*)) {
     throw "Unexpected run-time type: `new B().x` is ${x.{core::Object::runtimeType}}, but `_Y<Null>` expected";
   }
 }
diff --git a/pkg/front_end/testcases/general/constructor_const_inference.dart.strong.transformed.expect b/pkg/front_end/testcases/general/constructor_const_inference.dart.strong.transformed.expect
index 45d397e..c95b9b2 100644
--- a/pkg/front_end/testcases/general/constructor_const_inference.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/constructor_const_inference.dart.strong.transformed.expect
@@ -20,7 +20,7 @@
 }
 static method main() → dynamic {
   dynamic x = new self::B::•<dynamic>().{self::A::x};
-  if(!(x is self::_Y<core::Null*>*)) {
+  if(!(x is self::_Y<core::Null?>*)) {
     throw "Unexpected run-time type: `new B().x` is ${x.{core::Object::runtimeType}}, but `_Y<Null>` expected";
   }
 }
diff --git a/pkg/front_end/testcases/general/duplicated_declarations.dart.outline.expect b/pkg/front_end/testcases/general/duplicated_declarations.dart.outline.expect
index 1b8f882..b190f3a 100644
--- a/pkg/front_end/testcases/general/duplicated_declarations.dart.outline.expect
+++ b/pkg/front_end/testcases/general/duplicated_declarations.dart.outline.expect
@@ -306,10 +306,6 @@
 // class Sub extends C {
 //                   ^
 //
-// pkg/front_end/testcases/general/duplicated_declarations.dart:65:19: Error: 'C' isn't a type.
-// class Sub extends C {
-//                   ^
-//
 import self as self;
 import "dart:core" as core;
 
diff --git a/pkg/front_end/testcases/general/duplicated_declarations.dart.strong.expect b/pkg/front_end/testcases/general/duplicated_declarations.dart.strong.expect
index 1248ef1..71677b2 100644
--- a/pkg/front_end/testcases/general/duplicated_declarations.dart.strong.expect
+++ b/pkg/front_end/testcases/general/duplicated_declarations.dart.strong.expect
@@ -306,10 +306,6 @@
 // class Sub extends C {
 //                   ^
 //
-// pkg/front_end/testcases/general/duplicated_declarations.dart:65:19: Error: 'C' isn't a type.
-// class Sub extends C {
-//                   ^
-//
 // pkg/front_end/testcases/general/duplicated_declarations.dart:34:3: Error: Can't use 'main' because it is declared more than once.
 //   main();
 //   ^
diff --git a/pkg/front_end/testcases/general/export_main.dart.outline.expect b/pkg/front_end/testcases/general/export_main.dart.outline.expect
index ce25789..f618c7c 100644
--- a/pkg/front_end/testcases/general/export_main.dart.outline.expect
+++ b/pkg/front_end/testcases/general/export_main.dart.outline.expect
@@ -3,7 +3,6 @@
 import "hello.dart" as hel;
 additionalExports = (hel::main)
 
-
 export "org-dartlang-testcase:///hello.dart";
 
 
diff --git a/pkg/front_end/testcases/general/export_main.dart.strong.expect b/pkg/front_end/testcases/general/export_main.dart.strong.expect
index 2ce3772..2b405e0 100644
--- a/pkg/front_end/testcases/general/export_main.dart.strong.expect
+++ b/pkg/front_end/testcases/general/export_main.dart.strong.expect
@@ -3,7 +3,6 @@
 import "hello.dart" as hel;
 additionalExports = (hel::main)
 
-
 export "org-dartlang-testcase:///hello.dart";
 
 
diff --git a/pkg/front_end/testcases/general/export_main.dart.strong.transformed.expect b/pkg/front_end/testcases/general/export_main.dart.strong.transformed.expect
index 2ce3772..2b405e0 100644
--- a/pkg/front_end/testcases/general/export_main.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/export_main.dart.strong.transformed.expect
@@ -3,7 +3,6 @@
 import "hello.dart" as hel;
 additionalExports = (hel::main)
 
-
 export "org-dartlang-testcase:///hello.dart";
 
 
diff --git a/pkg/front_end/testcases/general/export_test.dart.outline.expect b/pkg/front_end/testcases/general/export_test.dart.outline.expect
index a49370d..f2dbda1 100644
--- a/pkg/front_end/testcases/general/export_test.dart.outline.expect
+++ b/pkg/front_end/testcases/general/export_test.dart.outline.expect
@@ -3,7 +3,6 @@
 import "dart:core" as core;
 additionalExports = (core::print)
 
-
 import "dart:developer";
 export "dart:core";
 
diff --git a/pkg/front_end/testcases/general/export_test.dart.strong.expect b/pkg/front_end/testcases/general/export_test.dart.strong.expect
index 3f5a303..21a39a9 100644
--- a/pkg/front_end/testcases/general/export_test.dart.strong.expect
+++ b/pkg/front_end/testcases/general/export_test.dart.strong.expect
@@ -4,7 +4,6 @@
 import "dart:developer" as dev;
 additionalExports = (core::print)
 
-
 import "dart:developer";
 export "dart:core";
 
diff --git a/pkg/front_end/testcases/general/export_test.dart.strong.transformed.expect b/pkg/front_end/testcases/general/export_test.dart.strong.transformed.expect
index 3f5a303..21a39a9 100644
--- a/pkg/front_end/testcases/general/export_test.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/export_test.dart.strong.transformed.expect
@@ -4,7 +4,6 @@
 import "dart:developer" as dev;
 additionalExports = (core::print)
 
-
 import "dart:developer";
 export "dart:core";
 
diff --git a/pkg/front_end/testcases/general/issue38812.dart b/pkg/front_end/testcases/general/issue38812.dart
new file mode 100644
index 0000000..9d26308
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue38812.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.
+
+typedef G<X> = void Function();
+
+class A<X extends G<A<Y, X>>, Y extends G<A<X, Y>>> {}
+
+main() {
+  A();
+}
diff --git a/pkg/front_end/testcases/general/issue38812.dart.outline.expect b/pkg/front_end/testcases/general/issue38812.dart.outline.expect
new file mode 100644
index 0000000..e3d6405
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue38812.dart.outline.expect
@@ -0,0 +1,11 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+typedef G<unrelated X extends core::Object* = dynamic> = () →* void;
+class A<X extends () →* void = () →* void, Y extends () →* void = () →* void> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X*, self::A::Y*>*
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/issue38812.dart.strong.expect b/pkg/front_end/testcases/general/issue38812.dart.strong.expect
new file mode 100644
index 0000000..638ba06
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue38812.dart.strong.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+typedef G<unrelated X extends core::Object* = dynamic> = () →* void;
+class A<X extends () →* void = () →* void, Y extends () →* void = () →* void> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X*, self::A::Y*>*
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  new self::A::•<() →* void, () →* void>();
+}
diff --git a/pkg/front_end/testcases/general/issue38812.dart.strong.transformed.expect b/pkg/front_end/testcases/general/issue38812.dart.strong.transformed.expect
new file mode 100644
index 0000000..638ba06
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue38812.dart.strong.transformed.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+typedef G<unrelated X extends core::Object* = dynamic> = () →* void;
+class A<X extends () →* void = () →* void, Y extends () →* void = () →* void> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X*, self::A::Y*>*
+    : super core::Object::•()
+    ;
+}
+static method main() → dynamic {
+  new self::A::•<() →* void, () →* void>();
+}
diff --git a/pkg/front_end/testcases/general/promoted_access.dart b/pkg/front_end/testcases/general/promoted_access.dart
new file mode 100644
index 0000000..6f6976f
--- /dev/null
+++ b/pkg/front_end/testcases/general/promoted_access.dart
@@ -0,0 +1,18 @@
+class Class<T> {
+  method(T o) {
+    if (o is Class) {
+      o.method(null);
+    }
+  }
+}
+
+method<T>(T o) {
+  if (o is Class) {
+    o.method(null);
+  }
+}
+
+main() {
+  new Class().method(new Class());
+  method(new Class());
+}
diff --git a/pkg/front_end/testcases/general/promoted_access.dart.outline.expect b/pkg/front_end/testcases/general/promoted_access.dart.outline.expect
new file mode 100644
index 0000000..255851a
--- /dev/null
+++ b/pkg/front_end/testcases/general/promoted_access.dart.outline.expect
@@ -0,0 +1,14 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::Class<self::Class::T*>*
+    ;
+  method method(generic-covariant-impl self::Class::T* o) → dynamic
+    ;
+}
+static method method<T extends core::Object* = dynamic>(self::method::T* o) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/promoted_access.dart.strong.expect b/pkg/front_end/testcases/general/promoted_access.dart.strong.expect
new file mode 100644
index 0000000..a16b916
--- /dev/null
+++ b/pkg/front_end/testcases/general/promoted_access.dart.strong.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::Class<self::Class::T*>*
+    : super core::Object::•()
+    ;
+  method method(generic-covariant-impl self::Class::T* o) → dynamic {
+    if(o is self::Class<dynamic>*) {
+      o{self::Class::T* & self::Class<dynamic>* /* '*' & '*' = '*' */}.{self::Class::method}(null);
+    }
+  }
+}
+static method method<T extends core::Object* = dynamic>(self::method::T* o) → dynamic {
+  if(o is self::Class<dynamic>*) {
+    o{self::method::T* & self::Class<dynamic>* /* '*' & '*' = '*' */}.{self::Class::method}(null);
+  }
+}
+static method main() → dynamic {
+  new self::Class::•<dynamic>().{self::Class::method}(new self::Class::•<dynamic>());
+  self::method<self::Class<dynamic>*>(new self::Class::•<dynamic>());
+}
diff --git a/pkg/front_end/testcases/general/promoted_access.dart.strong.transformed.expect b/pkg/front_end/testcases/general/promoted_access.dart.strong.transformed.expect
new file mode 100644
index 0000000..a16b916
--- /dev/null
+++ b/pkg/front_end/testcases/general/promoted_access.dart.strong.transformed.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Class<T extends core::Object* = dynamic> extends core::Object {
+  synthetic constructor •() → self::Class<self::Class::T*>*
+    : super core::Object::•()
+    ;
+  method method(generic-covariant-impl self::Class::T* o) → dynamic {
+    if(o is self::Class<dynamic>*) {
+      o{self::Class::T* & self::Class<dynamic>* /* '*' & '*' = '*' */}.{self::Class::method}(null);
+    }
+  }
+}
+static method method<T extends core::Object* = dynamic>(self::method::T* o) → dynamic {
+  if(o is self::Class<dynamic>*) {
+    o{self::method::T* & self::Class<dynamic>* /* '*' & '*' = '*' */}.{self::Class::method}(null);
+  }
+}
+static method main() → dynamic {
+  new self::Class::•<dynamic>().{self::Class::method}(new self::Class::•<dynamic>());
+  self::method<self::Class<dynamic>*>(new self::Class::•<dynamic>());
+}
diff --git a/pkg/front_end/testcases/general/promoted_access.dart.type_promotion.expect b/pkg/front_end/testcases/general/promoted_access.dart.type_promotion.expect
new file mode 100644
index 0000000..4f2344b
--- /dev/null
+++ b/pkg/front_end/testcases/general/promoted_access.dart.type_promotion.expect
@@ -0,0 +1,6 @@
+pkg/front_end/testcases/general/promoted_access.dart:3:11: Context: Possible promotion of o@28
+    if (o is Class) {
+          ^^
+pkg/front_end/testcases/general/promoted_access.dart:10:9: Context: Possible promotion of o@28
+  if (o is Class) {
+        ^^
diff --git a/pkg/front_end/testcases/general/redirecting_factory_const_inference.dart.strong.expect b/pkg/front_end/testcases/general/redirecting_factory_const_inference.dart.strong.expect
index 5f63429..87fc76e 100644
--- a/pkg/front_end/testcases/general/redirecting_factory_const_inference.dart.strong.expect
+++ b/pkg/front_end/testcases/general/redirecting_factory_const_inference.dart.strong.expect
@@ -25,7 +25,7 @@
 }
 static method main() → dynamic {
   dynamic x = new self::B::•<dynamic>().{self::A::x};
-  if(!(x is self::_Y<core::Null*>*)) {
+  if(!(x is self::_Y<core::Null?>*)) {
     throw "Unexpected run-time type: `new B().x` is ${x.{core::Object::runtimeType}}, but `_Y<Null>` expected";
   }
 }
diff --git a/pkg/front_end/testcases/general/redirecting_factory_const_inference.dart.strong.transformed.expect b/pkg/front_end/testcases/general/redirecting_factory_const_inference.dart.strong.transformed.expect
index a352dae88..0394311 100644
--- a/pkg/front_end/testcases/general/redirecting_factory_const_inference.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/redirecting_factory_const_inference.dart.strong.transformed.expect
@@ -25,7 +25,7 @@
 }
 static method main() → dynamic {
   dynamic x = new self::B::•<dynamic>().{self::A::x};
-  if(!(x is self::_Y<core::Null*>*)) {
+  if(!(x is self::_Y<core::Null?>*)) {
     throw "Unexpected run-time type: `new B().x` is ${x.{core::Object::runtimeType}}, but `_Y<Null>` expected";
   }
 }
diff --git a/pkg/front_end/testcases/general/type_of_null.dart b/pkg/front_end/testcases/general/type_of_null.dart
index 39db639..70292a1 100644
--- a/pkg/front_end/testcases/general/type_of_null.dart
+++ b/pkg/front_end/testcases/general/type_of_null.dart
@@ -15,9 +15,9 @@
   /*@ typeArgs=Null? */ map(/*@ returnType=<BottomType> */ () => throw "hello",
       /*@ returnType=Null? */ () {});
   Null Function() f = /*@ returnType=Null? */ () {};
-  /*@ typeArgs=Null* */ map(
+  /*@ typeArgs=Null? */ map(
       foo, /*@ returnType=<BottomType> */ () => throw "hello");
-  /*@ typeArgs=Null* */ map(
+  /*@ typeArgs=Null? */ map(
       /*@ returnType=<BottomType> */ () => throw "hello", foo);
   /*@ typeArgs=Null? */ map(/*@ returnType=Null? */ () {
     return null;
diff --git a/pkg/front_end/testcases/general/type_of_null.dart.outline.expect b/pkg/front_end/testcases/general/type_of_null.dart.outline.expect
index 336fdab..3485e02 100644
--- a/pkg/front_end/testcases/general/type_of_null.dart.outline.expect
+++ b/pkg/front_end/testcases/general/type_of_null.dart.outline.expect
@@ -6,7 +6,7 @@
   ;
 static method id<T extends core::Object* = dynamic>(self::id::T* t) → dynamic
   ;
-static method foo() → core::Null*
+static method foo() → core::Null?
   ;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/general/type_of_null.dart.strong.expect b/pkg/front_end/testcases/general/type_of_null.dart.strong.expect
index 40a4bed..c0c8997 100644
--- a/pkg/front_end/testcases/general/type_of_null.dart.strong.expect
+++ b/pkg/front_end/testcases/general/type_of_null.dart.strong.expect
@@ -5,14 +5,14 @@
 static method map<T extends core::Object* = dynamic>(() →* self::map::T* f1, () →* self::map::T* f2) → self::map::T* {}
 static method id<T extends core::Object* = dynamic>(self::id::T* t) → dynamic
   return t;
-static method foo() → core::Null*
+static method foo() → core::Null?
   return null;
 static method main() → dynamic {
   self::map<core::Null?>(() → core::Null? {}, () → <BottomType>=> throw "hello");
   self::map<core::Null?>(() → <BottomType>=> throw "hello", () → core::Null? {});
-  () →* core::Null* f = () → core::Null? {};
-  self::map<core::Null*>(#C1, () → <BottomType>=> throw "hello");
-  self::map<core::Null*>(() → <BottomType>=> throw "hello", #C1);
+  () →* core::Null? f = () → core::Null? {};
+  self::map<core::Null?>(#C1, () → <BottomType>=> throw "hello");
+  self::map<core::Null?>(() → <BottomType>=> throw "hello", #C1);
   self::map<core::Null?>(() → core::Null? {
     return null;
   }, () → <BottomType>=> throw "hello");
diff --git a/pkg/front_end/testcases/general/type_of_null.dart.strong.transformed.expect b/pkg/front_end/testcases/general/type_of_null.dart.strong.transformed.expect
index 40a4bed..c0c8997 100644
--- a/pkg/front_end/testcases/general/type_of_null.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/type_of_null.dart.strong.transformed.expect
@@ -5,14 +5,14 @@
 static method map<T extends core::Object* = dynamic>(() →* self::map::T* f1, () →* self::map::T* f2) → self::map::T* {}
 static method id<T extends core::Object* = dynamic>(self::id::T* t) → dynamic
   return t;
-static method foo() → core::Null*
+static method foo() → core::Null?
   return null;
 static method main() → dynamic {
   self::map<core::Null?>(() → core::Null? {}, () → <BottomType>=> throw "hello");
   self::map<core::Null?>(() → <BottomType>=> throw "hello", () → core::Null? {});
-  () →* core::Null* f = () → core::Null? {};
-  self::map<core::Null*>(#C1, () → <BottomType>=> throw "hello");
-  self::map<core::Null*>(() → <BottomType>=> throw "hello", #C1);
+  () →* core::Null? f = () → core::Null? {};
+  self::map<core::Null?>(#C1, () → <BottomType>=> throw "hello");
+  self::map<core::Null?>(() → <BottomType>=> throw "hello", #C1);
   self::map<core::Null?>(() → core::Null? {
     return null;
   }, () → <BottomType>=> throw "hello");
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_10.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_10.yaml
index d8a8994..c500317 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_10.yaml
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_10.yaml
@@ -20,6 +20,7 @@
       module:.
 worlds:
   - entry: main.dart
+    fromComponent: true
     sources:
       main.dart: |
         import 'package:module/a.dart';
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_11.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_11.yaml
index c4dc3df..e6d89f4 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_11.yaml
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_11.yaml
@@ -20,6 +20,7 @@
       module:.
 worlds:
   - entry: main.dart
+    fromComponent: true
     sources:
       main.dart: |
         import 'package:module/a.dart';
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_12.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_12.yaml
index 19a5268..21b9ec1 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_12.yaml
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_12.yaml
@@ -24,6 +24,7 @@
       module:.
 worlds:
   - entry: main.dart
+    fromComponent: true
     sources:
       main.dart: |
         class Foo {}
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_13.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_13.yaml
index f7261a4..bd3bc06 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_13.yaml
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_13.yaml
@@ -2,7 +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.md file.
 
-# Reproduction fo https://github.com/flutter/flutter/issues/40966.
+# Reproduction of https://github.com/flutter/flutter/issues/40966.
 
 type: newworld
 target: None
@@ -17,6 +17,7 @@
       module:.
 worlds:
   - entry: main.dart
+    fromComponent: true
     sources:
       main.dart: |
         import "package:module/a.dart";
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_7.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_7.yaml
index 07c9b1c..ed58e9d 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_7.yaml
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_7.yaml
@@ -79,6 +79,8 @@
       package:module/lib4.dart:
         - Class Class4
   - entry: compileme.dart
+    fromComponent: true
+    expectInitializeFromDill: false
     outlineOnly: true
     skipOutlineBodyCheck: true
     sources:
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_9.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_9.yaml
index 2a4d912..c810617 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_9.yaml
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/changing_modules_9.yaml
@@ -25,6 +25,7 @@
       moduleB:.
 worlds:
   - entry: main.dart
+    fromComponent: true
     sources:
       main.dart: |
         import "package:moduleA/a.dart";
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/cleans_up_uritosource_non_package_part.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/cleans_up_uritosource_non_package_part.yaml
new file mode 100644
index 0000000..e8a3d25
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/cleans_up_uritosource_non_package_part.yaml
@@ -0,0 +1,35 @@
+# 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 no packages and two libraries and a part.
+# Update the world to remove usage of the part. The now no longer referenced
+# part should also have been removed from the uri to sources.
+
+type: newworld
+worlds:
+  - entry: main.dart
+    sources:
+      main.dart: |
+        import "b.dart";
+        main() { b(); }
+      b.dart: |
+        part 'c.dart';
+        b() {
+          c();
+        }
+      c.dart: |
+        part of 'b.dart';
+        c() {}
+    expectedLibraryCount: 2
+  - entry: main.dart
+    worldType: updated
+    invalidate:
+      - b.dart
+    expectInitializeFromDill: false
+    sources:
+      b.dart: |
+        b() {}
+    expectedLibraryCount: 2
+    uriToSourcesDoesntInclude:
+      - c.dart
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/cleans_up_uritosource_non_package_part_if_unused.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/cleans_up_uritosource_non_package_part_if_unused.yaml
new file mode 100644
index 0000000..33a6226
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/cleans_up_uritosource_non_package_part_if_unused.yaml
@@ -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.md file.
+
+# Compile an application with no packages and two libraries and three parts.
+# Update the world to move usage of one part and stop importing the second
+# library. The still referenced (though moved) part should still exist in the
+# uri to sources, but the unreferenced library and parts should not.
+
+type: newworld
+worlds:
+  - entry: main.dart
+    sources:
+      main.dart: |
+        import "b.dart";
+        main() { b(); }
+      b.dart: |
+        library libFoo;
+        // The middle-part is the kept one.
+        part 'e.dart';
+        part 'c.dart';
+        part 'd.dart';
+        b() {
+          c();
+          d();
+          e();
+        }
+      c.dart: |
+        part of libFoo;
+        c() {}
+      d.dart: |
+        part of libFoo;
+        d() {}
+      e.dart: |
+        part of libFoo;
+        e() {}
+    expectedLibraryCount: 2
+  - entry: main.dart
+    worldType: updated
+    invalidate:
+      - main.dart
+    expectInitializeFromDill: false
+    sources:
+      main.dart: |
+        library libFoo;
+        part 'c.dart';
+        main() { c(); }
+    expectedLibraryCount: 1
+    uriToSourcesDoesntInclude:
+      - b.dart
+      - d.dart
+      - e.dart
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/cleans_up_uritosource_non_package_unreferenced_libraries.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/cleans_up_uritosource_non_package_unreferenced_libraries.yaml
index 8c256a6..7d5d86d 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/cleans_up_uritosource_non_package_unreferenced_libraries.yaml
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/cleans_up_uritosource_non_package_unreferenced_libraries.yaml
@@ -14,7 +14,13 @@
         import "b.dart";
         main() { b(); }
       b.dart: |
-        b() {}
+        part 'c.dart';
+        b() {
+          c();
+        }
+      c.dart: |
+        part of 'b.dart';
+        c() {}
     expectedLibraryCount: 2
   - entry: main.dart
     worldType: updated
@@ -27,6 +33,7 @@
     expectedLibraryCount: 1
     uriToSourcesDoesntInclude:
       - b.dart
+      - c.dart
   - entry: main.dart
     worldType: updated
     invalidate:
@@ -38,3 +45,4 @@
     expectedLibraryCount: 1
     uriToSourcesDoesntInclude:
       - b.dart
+      - c.dart
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/incremental_serialization_1.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/incremental_serialization_1.yaml
new file mode 100644
index 0000000..6c859f5
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/incremental_serialization_1.yaml
@@ -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.md file.
+
+# Check some basic incremental serialization functionality.
+
+type: newworld
+incrementalSerialization: true
+worlds:
+  - entry: main.dart
+    sources:
+      main.dart: |
+        import "dart:core";
+        import "package:package2/lib2.dart";
+        import "package:package2/lib3.dart";
+        main() {
+          lib2();
+          lib3();
+        }
+      package1/lib1.dart:
+        lib1() {
+          return 42;
+        }
+      package2/lib2.dart:
+        lib2() {
+          return 42;
+        }
+      package2/lib3.dart:
+        import "package:package1/lib1.dart";
+        lib3() {
+          return lib1();
+        }
+      .packages: |
+        package1:package1
+        package2:package2
+    expectedLibraryCount: 4
+    incrementalSerializationDoesWork: true
+  - entry: main.dart
+    worldType: updated
+    expectInitializeFromDill: false
+    invalidate:
+      - main.dart
+    sources:
+      main.dart: |
+        import "package:package1/lib1.dart";
+        main() {
+          lib1();
+        }
+    expectedLibraryCount: 2
+    incrementalSerializationDoesWork: true
+    serializationShouldNotInclude:
+      # It would be a weird bundling up if including package2 here.
+      - package:package2/lib2.dart
+      - package:package2/lib3.dart
+  - entry: main.dart
+    worldType: updated
+    expectInitializeFromDill: false
+    invalidate:
+      - main.dart
+    sources:
+      main.dart: |
+        import "package:package2/lib2.dart";
+        main() {
+          lib2();
+        }
+    expectedLibraryCount: 2
+    incrementalSerializationDoesWork: true
+    brandNewIncrementalSerializationAllowDifferent: true
+  - entry: main.dart
+    worldType: updated
+    expectInitializeFromDill: false
+    invalidate:
+      - main.dart
+      - package:package1/lib1.dart
+    sources:
+      main.dart: |
+        import "package:package2/lib2.dart";
+        main() {
+          lib2();
+        }
+      package1/lib1.dart:
+        lib1_1() {
+          return 42;
+        }
+    expectedLibraryCount: 2
+    incrementalSerializationDoesWork: true
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/incremental_serialization_2.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/incremental_serialization_2.yaml
new file mode 100644
index 0000000..9a0feaf
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/incremental_serialization_2.yaml
@@ -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.md file.
+
+# Check that we don't crash when doing an actual partial component
+# (an actual delta).
+
+type: newworld
+incrementalSerialization: true
+worlds:
+  - entry: main.dart
+    sources:
+      main.dart:
+        import "package:package1/lib1.dart";
+        import "package:package1/lib2.dart";
+        import "package:package1/lib3.dart";
+        main() {
+          lib1();
+          lib2();
+          lib3();
+        }
+      package1/lib1.dart:
+        lib1() {
+          return 42;
+        }
+      package1/lib2.dart:
+        lib2() {
+          return 42;
+        }
+      package1/lib3.dart:
+        import "package:package1/lib1.dart";
+        lib3() {
+          return lib1();
+        }
+      .packages: |
+        package1:package1
+    expectedLibraryCount: 4
+    incrementalSerializationDoesWork: true
+  - entry: main.dart
+    worldType: updated
+    expectInitializeFromDill: false
+    invalidate:
+      - package:package1/lib3.dart
+    sources:
+      package1/lib3.dart:
+        import "package:package1/lib1.dart";
+        lib3() {
+          return lib3_1();
+        }
+        lib3_1() {
+          return lib1();
+        }
+    expectedLibraryCount: 2
+    # Asking for a partial component, i.e. it's not self-contained.
+    noFullComponent: true
\ No newline at end of file
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/incremental_serialization_3.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/incremental_serialization_3.yaml
new file mode 100644
index 0000000..7801796
--- /dev/null
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/incremental_serialization_3.yaml
@@ -0,0 +1,87 @@
+# 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.
+
+# Check incremental serialization when loading from dill.
+# Try to make it different by forcing a Canonical Name from package2 to be used
+# in package1. Also try to force wrong order by having package1 depend on
+# package3 before depending on package2.
+
+type: newworld
+incrementalSerialization: true
+worlds:
+  - entry: main.dart
+    sources:
+      main.dart: |
+        import "dart:core";
+        import "package:package1/lib1_a.dart";
+        main() {
+          lib1();
+        }
+      package1/lib1_a.dart:
+        import "package:package3/lib3.dart" as lib3;
+        export "lib1_b.dart";
+        lib1a() {
+          lib3.lib3();
+        }
+      package1/lib1_b.dart:
+        import "package:package2/lib2.dart" as lib2;
+        lib1() {
+          return la(null);
+        }
+        la(lib2.Foo f) {
+          return 42;
+        }
+      package2/lib2.dart:
+        int f = 42;
+        class Foo {
+          static int y = 42;
+        }
+      package3/lib3.dart:
+        lib3() {
+          print("lib3");
+        }
+      .packages: |
+        package1:package1
+        package2:package2
+        package3:package3
+    expectedLibraryCount: 5
+    incrementalSerializationDoesWork: true
+  - entry: main.dart
+    expectInitializeFromDill: true
+    sources:
+      main.dart: |
+        import "dart:core";
+        import "package:package1/lib1_a.dart";
+        main() {
+          lib1();
+        }
+      package1/lib1_a.dart:
+        import "package:package3/lib3.dart" as lib3;
+        export "lib1_b.dart";
+        lib1a() {
+          lib3.lib3();
+        }
+      package1/lib1_b.dart:
+        import "package:package2/lib2.dart" as lib2;
+        lib1() {
+          return la(null);
+        }
+        la(lib2.Foo f) {
+          return 42;
+        }
+      package2/lib2.dart:
+        int f = 42;
+        class Foo {
+          static int y = 42;
+        }
+      package3/lib3.dart:
+        lib3() {
+          print("lib3");
+        }
+      .packages: |
+        package1:package1
+        package2:package2
+        package3:package3
+    expectedLibraryCount: 5
+    incrementalSerializationDoesWork: true
diff --git a/pkg/front_end/testcases/incremental_initialize_from_dill/omit_platform_works_3.yaml b/pkg/front_end/testcases/incremental_initialize_from_dill/omit_platform_works_3.yaml
index 450377b..2a6583b 100644
--- a/pkg/front_end/testcases/incremental_initialize_from_dill/omit_platform_works_3.yaml
+++ b/pkg/front_end/testcases/incremental_initialize_from_dill/omit_platform_works_3.yaml
@@ -74,6 +74,10 @@
         main() {
           print(lib() + "!!");
         }
+      lib.dart: |
+        lib() {
+          return "hello";
+        }
     expectedLibraryCount: 2
     expectsPlatform: true
     expectInitializeFromDill: true
diff --git a/pkg/front_end/testcases/inference/closure_param_null_to_object.dart.strong.expect b/pkg/front_end/testcases/inference/closure_param_null_to_object.dart.strong.expect
index 0bd9702..e4b0faf 100644
--- a/pkg/front_end/testcases/inference/closure_param_null_to_object.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/closure_param_null_to_object.dart.strong.expect
@@ -3,6 +3,6 @@
 import "dart:core" as core;
 
 static method test() → void {
-  (core::Null*) →* core::int* f = (core::Object* x) → core::int* => 1;
+  (core::Null?) →* core::int* f = (core::Object* x) → core::int* => 1;
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference/closure_param_null_to_object.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/closure_param_null_to_object.dart.strong.transformed.expect
index 0bd9702..e4b0faf 100644
--- a/pkg/front_end/testcases/inference/closure_param_null_to_object.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/closure_param_null_to_object.dart.strong.transformed.expect
@@ -3,6 +3,6 @@
 import "dart:core" as core;
 
 static method test() → void {
-  (core::Null*) →* core::int* f = (core::Object* x) → core::int* => 1;
+  (core::Null?) →* core::int* f = (core::Object* x) → core::int* => 1;
 }
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference/override_equals.dart.outline.expect b/pkg/front_end/testcases/inference/override_equals.dart.outline.expect
index 7a2bc9e..904c032 100644
--- a/pkg/front_end/testcases/inference/override_equals.dart.outline.expect
+++ b/pkg/front_end/testcases/inference/override_equals.dart.outline.expect
@@ -6,7 +6,7 @@
   synthetic constructor •() → self::NullEquality*
     ;
   @core::override
-  operator ==(core::Object* other) → core::Null*
+  operator ==(core::Object* other) → core::Null?
     ;
 }
 class SubNullEquality extends self::NullEquality {
diff --git a/pkg/front_end/testcases/inference/override_equals.dart.strong.expect b/pkg/front_end/testcases/inference/override_equals.dart.strong.expect
index 83704d2..6bf9ce2 100644
--- a/pkg/front_end/testcases/inference/override_equals.dart.strong.expect
+++ b/pkg/front_end/testcases/inference/override_equals.dart.strong.expect
@@ -7,7 +7,7 @@
     : super core::Object::•()
     ;
   @#C1
-  operator ==(core::Object* other) → core::Null*
+  operator ==(core::Object* other) → core::Null?
     return null;
 }
 class SubNullEquality extends self::NullEquality {
diff --git a/pkg/front_end/testcases/inference/override_equals.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/override_equals.dart.strong.transformed.expect
index 83704d2..6bf9ce2 100644
--- a/pkg/front_end/testcases/inference/override_equals.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/inference/override_equals.dart.strong.transformed.expect
@@ -7,7 +7,7 @@
     : super core::Object::•()
     ;
   @#C1
-  operator ==(core::Object* other) → core::Null*
+  operator ==(core::Object* other) → core::Null?
     return null;
 }
 class SubNullEquality extends self::NullEquality {
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.outline.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.outline.expect
index 450c215..0d5534f 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.outline.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.outline.expect
@@ -13,7 +13,7 @@
   synthetic constructor •() → self::Hest<self::Hest::TypeX*>*
     ;
 }
-class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null*>* = dynamic>(TypeZ*) →* dynamic = dynamic> extends core::Object {
+class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null?>* = dynamic>(TypeZ*) →* dynamic = dynamic> extends core::Object {
   synthetic constructor •() → self::Fisk<self::Fisk::TypeY*>*
     ;
 }
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.expect
index 8f79b89..e37cda4 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.expect
@@ -14,7 +14,7 @@
     : super core::Object::•()
     ;
 }
-class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null*>* = dynamic>(TypeZ*) →* dynamic = dynamic> extends core::Object {
+class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null?>* = dynamic>(TypeZ*) →* dynamic = dynamic> extends core::Object {
   synthetic constructor •() → self::Fisk<self::Fisk::TypeY*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.transformed.expect b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.transformed.expect
index 8f79b89..e37cda4 100644
--- a/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/instantiate_to_bound/non_simple_generic_function_in_bound_regress.dart.strong.transformed.expect
@@ -14,7 +14,7 @@
     : super core::Object::•()
     ;
 }
-class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null*>* = dynamic>(TypeZ*) →* dynamic = dynamic> extends core::Object {
+class Fisk<TypeY extends <TypeZ extends self::Hest<core::Null?>* = dynamic>(TypeZ*) →* dynamic = dynamic> extends core::Object {
   synthetic constructor •() → self::Fisk<self::Fisk::TypeY*>*
     : super core::Object::•()
     ;
diff --git a/pkg/front_end/testcases/nested_variance_test.dart.strong.expect b/pkg/front_end/testcases/nested_variance_test.dart.strong.expect
index 44abf90..8d2d71d 100644
--- a/pkg/front_end/testcases/nested_variance_test.dart.strong.expect
+++ b/pkg/front_end/testcases/nested_variance_test.dart.strong.expect
@@ -93,7 +93,7 @@
   <Y extends self::Acov<() →* dynamic, dynamic>* = dynamic>() →* void target1 = fsource1;
   self::Acon<(core::Null?) →* dynamic, dynamic>* source2;
   <Y extends self::Acon<(core::Null?) →* dynamic, dynamic>* = dynamic>() →* void fsource2 = self::toF<self::Acon<(core::Null?) →* dynamic, dynamic>*>(source2);
-  <Y extends self::Acon<(core::Null*) →* dynamic, dynamic>* = dynamic>() →* void target2 = fsource2;
+  <Y extends self::Acon<(core::Null?) →* dynamic, dynamic>* = dynamic>() →* void target2 = fsource2;
   self::Ainv<(dynamic) →* dynamic, dynamic>* source3;
   <Y extends self::Ainv<(dynamic) →* dynamic, dynamic>* = dynamic>() →* void fsource3 = self::toF<self::Ainv<(dynamic) →* dynamic, dynamic>*>(source3);
   <Y extends self::Ainv<(dynamic) →* dynamic, dynamic>* = dynamic>() →* void target3 = fsource3;
@@ -102,7 +102,7 @@
   <Y extends self::AcovBound<() →* core::num*, core::num*>* = dynamic>() →* void target4 = fsource4;
   self::AconBound<(core::Null?) →* dynamic, core::num*>* source5;
   <Y extends self::AconBound<(core::Null?) →* dynamic, core::num*>* = dynamic>() →* void fsource5 = self::toF<self::AconBound<(core::Null?) →* dynamic, core::num*>*>(source5);
-  <Y extends self::AconBound<(core::Null*) →* dynamic, core::num*>* = dynamic>() →* void target5 = fsource5;
+  <Y extends self::AconBound<(core::Null?) →* dynamic, core::num*>* = dynamic>() →* void target5 = fsource5;
   self::AinvBound<(core::num*) →* core::num*, core::num*>* source6;
   <Y extends self::AinvBound<(core::num*) →* core::num*, core::num*>* = dynamic>() →* void fsource6 = self::toF<self::AinvBound<(core::num*) →* core::num*, core::num*>*>(source6);
   <Y extends self::AinvBound<(core::num*) →* core::num*, core::num*>* = dynamic>() →* void target6 = fsource6;
@@ -111,14 +111,14 @@
   <Y extends self::AcovCyclicBound<() →* self::A<dynamic>*, self::A<dynamic>*>* = dynamic>() →* void target7 = fsource7;
   self::AconCyclicBound<(core::Null?) →* dynamic, self::A<dynamic>*>* source8;
   <Y extends self::AconCyclicBound<(core::Null?) →* dynamic, self::A<dynamic>*>* = dynamic>() →* void fsource8 = self::toF<self::AconCyclicBound<(core::Null?) →* dynamic, self::A<dynamic>*>*>(source8);
-  <Y extends self::AconCyclicBound<(core::Null*) →* dynamic, self::A<dynamic>*>* = dynamic>() →* void target8 = fsource8;
+  <Y extends self::AconCyclicBound<(core::Null?) →* dynamic, self::A<dynamic>*>* = dynamic>() →* void target8 = fsource8;
   self::AinvCyclicBound<(self::A<dynamic>*) →* self::A<dynamic>*, self::A<dynamic>*>* source9;
   self::AcovCyclicCoBound<() →* (core::Null?) →* dynamic, (core::Null?) →* dynamic>* source10;
   <Y extends self::AcovCyclicCoBound<() →* (core::Null?) →* dynamic, (core::Null?) →* dynamic>* = dynamic>() →* void fsource10 = self::toF<self::AcovCyclicCoBound<() →* (core::Null?) →* dynamic, (core::Null?) →* dynamic>*>(source10);
-  <Y extends self::AcovCyclicCoBound<() →* (core::Null*) →* dynamic, (core::Null*) →* dynamic>* = dynamic>() →* void target10 = fsource10;
+  <Y extends self::AcovCyclicCoBound<() →* (core::Null?) →* dynamic, (core::Null?) →* dynamic>* = dynamic>() →* void target10 = fsource10;
   self::AconCyclicCoBound<(core::Null?) →* dynamic, (core::Null?) →* dynamic>* source11;
   <Y extends self::AconCyclicCoBound<(core::Null?) →* dynamic, (core::Null?) →* dynamic>* = dynamic>() →* void fsource11 = self::toF<self::AconCyclicCoBound<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>(source11);
-  <Y extends self::AconCyclicCoBound<(core::Null*) →* dynamic, (core::Null*) →* dynamic>* = dynamic>() →* void target11 = fsource11;
+  <Y extends self::AconCyclicCoBound<(core::Null?) →* dynamic, (core::Null?) →* dynamic>* = dynamic>() →* void target11 = fsource11;
   self::AinvCyclicCoBound<((core::Null?) →* dynamic) →* (core::Null?) →* dynamic, (core::Null?) →* dynamic>* source12;
 }
 static method testNested() → void {
@@ -127,7 +127,7 @@
   <Y extends self::B<self::Acov<() →* dynamic, dynamic>*>* = dynamic>() →* void target1 = fsource1;
   self::B<self::Acon<(core::Null?) →* dynamic, dynamic>*>* source2;
   <Y extends self::B<self::Acon<(core::Null?) →* dynamic, dynamic>*>* = dynamic>() →* void fsource2 = self::toF<self::B<self::Acon<(core::Null?) →* dynamic, dynamic>*>*>(source2);
-  <Y extends self::B<self::Acon<(core::Null*) →* dynamic, dynamic>*>* = dynamic>() →* void target2 = fsource2;
+  <Y extends self::B<self::Acon<(core::Null?) →* dynamic, dynamic>*>* = dynamic>() →* void target2 = fsource2;
   self::B<self::Ainv<(dynamic) →* dynamic, dynamic>*>* source3;
   <Y extends self::B<self::Ainv<(dynamic) →* dynamic, dynamic>*>* = dynamic>() →* void fsource3 = self::toF<self::B<self::Ainv<(dynamic) →* dynamic, dynamic>*>*>(source3);
   <Y extends self::B<self::Ainv<(dynamic) →* dynamic, dynamic>*>* = dynamic>() →* void target3 = fsource3;
@@ -136,7 +136,7 @@
   <Y extends self::B<self::AcovBound<() →* core::num*, core::num*>*>* = dynamic>() →* void target4 = fsource4;
   self::B<self::AconBound<(core::Null?) →* dynamic, core::num*>*>* source5;
   <Y extends self::B<self::AconBound<(core::Null?) →* dynamic, core::num*>*>* = dynamic>() →* void fsource5 = self::toF<self::B<self::AconBound<(core::Null?) →* dynamic, core::num*>*>*>(source5);
-  <Y extends self::B<self::AconBound<(core::Null*) →* dynamic, core::num*>*>* = dynamic>() →* void target5 = fsource5;
+  <Y extends self::B<self::AconBound<(core::Null?) →* dynamic, core::num*>*>* = dynamic>() →* void target5 = fsource5;
   self::B<self::AinvBound<(core::num*) →* core::num*, core::num*>*>* source6;
   <Y extends self::B<self::AinvBound<(core::num*) →* core::num*, core::num*>*>* = dynamic>() →* void fsource6 = self::toF<self::B<self::AinvBound<(core::num*) →* core::num*, core::num*>*>*>(source6);
   <Y extends self::B<self::AinvBound<(core::num*) →* core::num*, core::num*>*>* = dynamic>() →* void target6 = fsource6;
@@ -145,14 +145,14 @@
   <Y extends self::B<self::AcovCyclicBound<() →* self::A<dynamic>*, self::A<dynamic>*>*>* = dynamic>() →* void target7 = fsource7;
   self::B<self::AconCyclicBound<(core::Null?) →* dynamic, self::A<dynamic>*>*>* source8;
   <Y extends self::B<self::AconCyclicBound<(core::Null?) →* dynamic, self::A<dynamic>*>*>* = dynamic>() →* void fsource8 = self::toF<self::B<self::AconCyclicBound<(core::Null?) →* dynamic, self::A<dynamic>*>*>*>(source8);
-  <Y extends self::B<self::AconCyclicBound<(core::Null*) →* dynamic, self::A<dynamic>*>*>* = dynamic>() →* void target8 = fsource8;
+  <Y extends self::B<self::AconCyclicBound<(core::Null?) →* dynamic, self::A<dynamic>*>*>* = dynamic>() →* void target8 = fsource8;
   self::B<self::AinvCyclicBound<(self::A<dynamic>*) →* self::A<dynamic>*, self::A<dynamic>*>*>* source9;
   self::B<self::AcovCyclicCoBound<() →* (core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* source10;
   <Y extends self::B<self::AcovCyclicCoBound<() →* (core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* = dynamic>() →* void fsource10 = self::toF<self::B<self::AcovCyclicCoBound<() →* (core::Null?) →* dynamic, (core::Null?) →* dynamic>*>*>(source10);
-  <Y extends self::B<self::AcovCyclicCoBound<() →* (core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* = dynamic>() →* void target10 = fsource10;
+  <Y extends self::B<self::AcovCyclicCoBound<() →* (core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* = dynamic>() →* void target10 = fsource10;
   self::B<self::AconCyclicCoBound<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* source11;
   <Y extends self::B<self::AconCyclicCoBound<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* = dynamic>() →* void fsource11 = self::toF<self::B<self::AconCyclicCoBound<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>*>(source11);
-  <Y extends self::B<self::AconCyclicCoBound<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* = dynamic>() →* void target11 = fsource11;
+  <Y extends self::B<self::AconCyclicCoBound<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* = dynamic>() →* void target11 = fsource11;
   self::B<self::AinvCyclicCoBound<((core::Null?) →* dynamic) →* (core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* source12;
 }
 static method main() → dynamic {
diff --git a/pkg/front_end/testcases/nested_variance_test.dart.strong.transformed.expect b/pkg/front_end/testcases/nested_variance_test.dart.strong.transformed.expect
index 44abf90..8d2d71d 100644
--- a/pkg/front_end/testcases/nested_variance_test.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nested_variance_test.dart.strong.transformed.expect
@@ -93,7 +93,7 @@
   <Y extends self::Acov<() →* dynamic, dynamic>* = dynamic>() →* void target1 = fsource1;
   self::Acon<(core::Null?) →* dynamic, dynamic>* source2;
   <Y extends self::Acon<(core::Null?) →* dynamic, dynamic>* = dynamic>() →* void fsource2 = self::toF<self::Acon<(core::Null?) →* dynamic, dynamic>*>(source2);
-  <Y extends self::Acon<(core::Null*) →* dynamic, dynamic>* = dynamic>() →* void target2 = fsource2;
+  <Y extends self::Acon<(core::Null?) →* dynamic, dynamic>* = dynamic>() →* void target2 = fsource2;
   self::Ainv<(dynamic) →* dynamic, dynamic>* source3;
   <Y extends self::Ainv<(dynamic) →* dynamic, dynamic>* = dynamic>() →* void fsource3 = self::toF<self::Ainv<(dynamic) →* dynamic, dynamic>*>(source3);
   <Y extends self::Ainv<(dynamic) →* dynamic, dynamic>* = dynamic>() →* void target3 = fsource3;
@@ -102,7 +102,7 @@
   <Y extends self::AcovBound<() →* core::num*, core::num*>* = dynamic>() →* void target4 = fsource4;
   self::AconBound<(core::Null?) →* dynamic, core::num*>* source5;
   <Y extends self::AconBound<(core::Null?) →* dynamic, core::num*>* = dynamic>() →* void fsource5 = self::toF<self::AconBound<(core::Null?) →* dynamic, core::num*>*>(source5);
-  <Y extends self::AconBound<(core::Null*) →* dynamic, core::num*>* = dynamic>() →* void target5 = fsource5;
+  <Y extends self::AconBound<(core::Null?) →* dynamic, core::num*>* = dynamic>() →* void target5 = fsource5;
   self::AinvBound<(core::num*) →* core::num*, core::num*>* source6;
   <Y extends self::AinvBound<(core::num*) →* core::num*, core::num*>* = dynamic>() →* void fsource6 = self::toF<self::AinvBound<(core::num*) →* core::num*, core::num*>*>(source6);
   <Y extends self::AinvBound<(core::num*) →* core::num*, core::num*>* = dynamic>() →* void target6 = fsource6;
@@ -111,14 +111,14 @@
   <Y extends self::AcovCyclicBound<() →* self::A<dynamic>*, self::A<dynamic>*>* = dynamic>() →* void target7 = fsource7;
   self::AconCyclicBound<(core::Null?) →* dynamic, self::A<dynamic>*>* source8;
   <Y extends self::AconCyclicBound<(core::Null?) →* dynamic, self::A<dynamic>*>* = dynamic>() →* void fsource8 = self::toF<self::AconCyclicBound<(core::Null?) →* dynamic, self::A<dynamic>*>*>(source8);
-  <Y extends self::AconCyclicBound<(core::Null*) →* dynamic, self::A<dynamic>*>* = dynamic>() →* void target8 = fsource8;
+  <Y extends self::AconCyclicBound<(core::Null?) →* dynamic, self::A<dynamic>*>* = dynamic>() →* void target8 = fsource8;
   self::AinvCyclicBound<(self::A<dynamic>*) →* self::A<dynamic>*, self::A<dynamic>*>* source9;
   self::AcovCyclicCoBound<() →* (core::Null?) →* dynamic, (core::Null?) →* dynamic>* source10;
   <Y extends self::AcovCyclicCoBound<() →* (core::Null?) →* dynamic, (core::Null?) →* dynamic>* = dynamic>() →* void fsource10 = self::toF<self::AcovCyclicCoBound<() →* (core::Null?) →* dynamic, (core::Null?) →* dynamic>*>(source10);
-  <Y extends self::AcovCyclicCoBound<() →* (core::Null*) →* dynamic, (core::Null*) →* dynamic>* = dynamic>() →* void target10 = fsource10;
+  <Y extends self::AcovCyclicCoBound<() →* (core::Null?) →* dynamic, (core::Null?) →* dynamic>* = dynamic>() →* void target10 = fsource10;
   self::AconCyclicCoBound<(core::Null?) →* dynamic, (core::Null?) →* dynamic>* source11;
   <Y extends self::AconCyclicCoBound<(core::Null?) →* dynamic, (core::Null?) →* dynamic>* = dynamic>() →* void fsource11 = self::toF<self::AconCyclicCoBound<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>(source11);
-  <Y extends self::AconCyclicCoBound<(core::Null*) →* dynamic, (core::Null*) →* dynamic>* = dynamic>() →* void target11 = fsource11;
+  <Y extends self::AconCyclicCoBound<(core::Null?) →* dynamic, (core::Null?) →* dynamic>* = dynamic>() →* void target11 = fsource11;
   self::AinvCyclicCoBound<((core::Null?) →* dynamic) →* (core::Null?) →* dynamic, (core::Null?) →* dynamic>* source12;
 }
 static method testNested() → void {
@@ -127,7 +127,7 @@
   <Y extends self::B<self::Acov<() →* dynamic, dynamic>*>* = dynamic>() →* void target1 = fsource1;
   self::B<self::Acon<(core::Null?) →* dynamic, dynamic>*>* source2;
   <Y extends self::B<self::Acon<(core::Null?) →* dynamic, dynamic>*>* = dynamic>() →* void fsource2 = self::toF<self::B<self::Acon<(core::Null?) →* dynamic, dynamic>*>*>(source2);
-  <Y extends self::B<self::Acon<(core::Null*) →* dynamic, dynamic>*>* = dynamic>() →* void target2 = fsource2;
+  <Y extends self::B<self::Acon<(core::Null?) →* dynamic, dynamic>*>* = dynamic>() →* void target2 = fsource2;
   self::B<self::Ainv<(dynamic) →* dynamic, dynamic>*>* source3;
   <Y extends self::B<self::Ainv<(dynamic) →* dynamic, dynamic>*>* = dynamic>() →* void fsource3 = self::toF<self::B<self::Ainv<(dynamic) →* dynamic, dynamic>*>*>(source3);
   <Y extends self::B<self::Ainv<(dynamic) →* dynamic, dynamic>*>* = dynamic>() →* void target3 = fsource3;
@@ -136,7 +136,7 @@
   <Y extends self::B<self::AcovBound<() →* core::num*, core::num*>*>* = dynamic>() →* void target4 = fsource4;
   self::B<self::AconBound<(core::Null?) →* dynamic, core::num*>*>* source5;
   <Y extends self::B<self::AconBound<(core::Null?) →* dynamic, core::num*>*>* = dynamic>() →* void fsource5 = self::toF<self::B<self::AconBound<(core::Null?) →* dynamic, core::num*>*>*>(source5);
-  <Y extends self::B<self::AconBound<(core::Null*) →* dynamic, core::num*>*>* = dynamic>() →* void target5 = fsource5;
+  <Y extends self::B<self::AconBound<(core::Null?) →* dynamic, core::num*>*>* = dynamic>() →* void target5 = fsource5;
   self::B<self::AinvBound<(core::num*) →* core::num*, core::num*>*>* source6;
   <Y extends self::B<self::AinvBound<(core::num*) →* core::num*, core::num*>*>* = dynamic>() →* void fsource6 = self::toF<self::B<self::AinvBound<(core::num*) →* core::num*, core::num*>*>*>(source6);
   <Y extends self::B<self::AinvBound<(core::num*) →* core::num*, core::num*>*>* = dynamic>() →* void target6 = fsource6;
@@ -145,14 +145,14 @@
   <Y extends self::B<self::AcovCyclicBound<() →* self::A<dynamic>*, self::A<dynamic>*>*>* = dynamic>() →* void target7 = fsource7;
   self::B<self::AconCyclicBound<(core::Null?) →* dynamic, self::A<dynamic>*>*>* source8;
   <Y extends self::B<self::AconCyclicBound<(core::Null?) →* dynamic, self::A<dynamic>*>*>* = dynamic>() →* void fsource8 = self::toF<self::B<self::AconCyclicBound<(core::Null?) →* dynamic, self::A<dynamic>*>*>*>(source8);
-  <Y extends self::B<self::AconCyclicBound<(core::Null*) →* dynamic, self::A<dynamic>*>*>* = dynamic>() →* void target8 = fsource8;
+  <Y extends self::B<self::AconCyclicBound<(core::Null?) →* dynamic, self::A<dynamic>*>*>* = dynamic>() →* void target8 = fsource8;
   self::B<self::AinvCyclicBound<(self::A<dynamic>*) →* self::A<dynamic>*, self::A<dynamic>*>*>* source9;
   self::B<self::AcovCyclicCoBound<() →* (core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* source10;
   <Y extends self::B<self::AcovCyclicCoBound<() →* (core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* = dynamic>() →* void fsource10 = self::toF<self::B<self::AcovCyclicCoBound<() →* (core::Null?) →* dynamic, (core::Null?) →* dynamic>*>*>(source10);
-  <Y extends self::B<self::AcovCyclicCoBound<() →* (core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* = dynamic>() →* void target10 = fsource10;
+  <Y extends self::B<self::AcovCyclicCoBound<() →* (core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* = dynamic>() →* void target10 = fsource10;
   self::B<self::AconCyclicCoBound<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* source11;
   <Y extends self::B<self::AconCyclicCoBound<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* = dynamic>() →* void fsource11 = self::toF<self::B<self::AconCyclicCoBound<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>*>(source11);
-  <Y extends self::B<self::AconCyclicCoBound<(core::Null*) →* dynamic, (core::Null*) →* dynamic>*>* = dynamic>() →* void target11 = fsource11;
+  <Y extends self::B<self::AconCyclicCoBound<(core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* = dynamic>() →* void target11 = fsource11;
   self::B<self::AinvCyclicCoBound<((core::Null?) →* dynamic) →* (core::Null?) →* dynamic, (core::Null?) →* dynamic>*>* source12;
 }
 static method main() → dynamic {
diff --git a/pkg/front_end/testcases/nnbd/nullable_null.dart b/pkg/front_end/testcases/nnbd/nullable_null.dart
new file mode 100644
index 0000000..af054ea
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nullable_null.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.
+
+// The test checks that Null is nullable.
+
+class A<X> {}
+
+class B extends A<Null> {}
+
+class C {
+  Null foo(Null n, A<Null> an) => n;
+}
+
+foo() {
+  return [<Null>[], <A<Null>>[]];
+}
+
+bar() {
+  return [const <Null>[], const <A<Null>>[]];
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/nullable_null.dart.outline.expect b/pkg/front_end/testcases/nnbd/nullable_null.dart.outline.expect
new file mode 100644
index 0000000..f782516
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nullable_null.dart.outline.expect
@@ -0,0 +1,24 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X*>*
+    ;
+}
+class B extends self::A<core::Null?> {
+  synthetic constructor •() → self::B*
+    ;
+}
+class C extends core::Object {
+  synthetic constructor •() → self::C*
+    ;
+  method foo(core::Null? n, self::A<core::Null?> an) → core::Null?
+    ;
+}
+static method foo() → dynamic
+  ;
+static method bar() → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/nnbd/nullable_null.dart.strong.expect b/pkg/front_end/testcases/nnbd/nullable_null.dart.strong.expect
new file mode 100644
index 0000000..8d9c779
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nullable_null.dart.strong.expect
@@ -0,0 +1,33 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X*>*
+    : super core::Object::•()
+    ;
+}
+class B extends self::A<core::Null?> {
+  synthetic constructor •() → self::B*
+    : super self::A::•()
+    ;
+}
+class C extends core::Object {
+  synthetic constructor •() → self::C*
+    : super core::Object::•()
+    ;
+  method foo(core::Null? n, self::A<core::Null?> an) → core::Null?
+    return n;
+}
+static method foo() → dynamic {
+  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];
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = <core::Null?>[]
+  #C2 = <self::A<core::Null?>>[]
+}
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
new file mode 100644
index 0000000..8d9c779
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/nullable_null.dart.strong.transformed.expect
@@ -0,0 +1,33 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<X extends core::Object? = dynamic> extends core::Object {
+  synthetic constructor •() → self::A<self::A::X*>*
+    : super core::Object::•()
+    ;
+}
+class B extends self::A<core::Null?> {
+  synthetic constructor •() → self::B*
+    : super self::A::•()
+    ;
+}
+class C extends core::Object {
+  synthetic constructor •() → self::C*
+    : super core::Object::•()
+    ;
+  method foo(core::Null? n, self::A<core::Null?> an) → core::Null?
+    return n;
+}
+static method foo() → dynamic {
+  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];
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = <core::Null?>[]
+  #C2 = <self::A<core::Null?>>[]
+}
diff --git a/pkg/front_end/testcases/old_dills/dart2js.version.35.compile.1.dill b/pkg/front_end/testcases/old_dills/dart2js.version.35.compile.1.dill
new file mode 100644
index 0000000..efeba88
--- /dev/null
+++ b/pkg/front_end/testcases/old_dills/dart2js.version.35.compile.1.dill
Binary files differ
diff --git a/pkg/front_end/testcases/rasta/class_hierarchy.dart.outline.expect b/pkg/front_end/testcases/rasta/class_hierarchy.dart.outline.expect
index 256fe64..db36893 100644
--- a/pkg/front_end/testcases/rasta/class_hierarchy.dart.outline.expect
+++ b/pkg/front_end/testcases/rasta/class_hierarchy.dart.outline.expect
@@ -22,9 +22,9 @@
 //   factory D() = Missing;
 //                 ^
 //
-// pkg/front_end/testcases/rasta/class_hierarchy.dart:12:11: Error: Redirection constructor target not found: 'Missing'
+// pkg/front_end/testcases/rasta/class_hierarchy.dart:12:17: Error: Redirection constructor target not found: 'Missing'
 //   factory D() = Missing;
-//           ^
+//                 ^
 //
 import self as self;
 import "dart:core" as core;
diff --git a/pkg/front_end/testcases/rasta/class_hierarchy.dart.strong.expect b/pkg/front_end/testcases/rasta/class_hierarchy.dart.strong.expect
index cce1bc5..c31d7a4 100644
--- a/pkg/front_end/testcases/rasta/class_hierarchy.dart.strong.expect
+++ b/pkg/front_end/testcases/rasta/class_hierarchy.dart.strong.expect
@@ -22,13 +22,9 @@
 //   factory D() = Missing;
 //                 ^
 //
-// pkg/front_end/testcases/rasta/class_hierarchy.dart:12:11: Error: Redirection constructor target not found: 'Missing'
+// pkg/front_end/testcases/rasta/class_hierarchy.dart:12:17: Error: Redirection constructor target not found: 'Missing'
 //   factory D() = Missing;
-//           ^
-//
-// pkg/front_end/testcases/rasta/class_hierarchy.dart:12:11: Error: Method not found: 'Missing'.
-//   factory D() = Missing;
-//           ^^^^^^^
+//                 ^
 //
 import self as self;
 import "dart:core" as core;
@@ -57,7 +53,7 @@
   new self::A::•();
   new self::B::•();
   new self::C::•();
-  invalid-expression "pkg/front_end/testcases/rasta/class_hierarchy.dart:12:11: Error: Method not found: 'Missing'.
-  factory D() = Missing;
-          ^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/rasta/class_hierarchy.dart:19:7: Error: Method not found: 'Missing'.
+  new D();
+      ^";
 }
diff --git a/pkg/front_end/testcases/rasta/class_hierarchy.dart.strong.transformed.expect b/pkg/front_end/testcases/rasta/class_hierarchy.dart.strong.transformed.expect
index 971b579..78b0fc3 100644
--- a/pkg/front_end/testcases/rasta/class_hierarchy.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/rasta/class_hierarchy.dart.strong.transformed.expect
@@ -22,13 +22,9 @@
 //   factory D() = Missing;
 //                 ^
 //
-// pkg/front_end/testcases/rasta/class_hierarchy.dart:12:11: Error: Redirection constructor target not found: 'Missing'
+// pkg/front_end/testcases/rasta/class_hierarchy.dart:12:17: Error: Redirection constructor target not found: 'Missing'
 //   factory D() = Missing;
-//           ^
-//
-// pkg/front_end/testcases/rasta/class_hierarchy.dart:12:11: Error: Method not found: 'Missing'.
-//   factory D() = Missing;
-//           ^^^^^^^
+//                 ^
 //
 import self as self;
 import "dart:core" as core;
@@ -57,7 +53,7 @@
   new self::A::•();
   new self::B::•();
   new self::C::•();
-  invalid-expression "pkg/front_end/testcases/rasta/class_hierarchy.dart:12:11: Error: Method not found: 'Missing'.
-  factory D() = Missing;
-          ^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/rasta/class_hierarchy.dart:19:7: Error: Method not found: 'Missing'.
+  new D();
+      ^";
 }
diff --git a/pkg/front_end/testcases/rasta/export.dart.outline.expect b/pkg/front_end/testcases/rasta/export.dart.outline.expect
index 2314e9e..e2ffc83 100644
--- a/pkg/front_end/testcases/rasta/export.dart.outline.expect
+++ b/pkg/front_end/testcases/rasta/export.dart.outline.expect
@@ -3,7 +3,6 @@
 import "foo.dart" as foo;
 additionalExports = (foo::foo)
 
-
 export "org-dartlang-testcase:///foo.dart";
 
 
diff --git a/pkg/front_end/testcases/rasta/export.dart.strong.expect b/pkg/front_end/testcases/rasta/export.dart.strong.expect
index b0410f4..6eb1e47 100644
--- a/pkg/front_end/testcases/rasta/export.dart.strong.expect
+++ b/pkg/front_end/testcases/rasta/export.dart.strong.expect
@@ -3,7 +3,6 @@
 import "foo.dart" as foo;
 additionalExports = (foo::foo)
 
-
 export "org-dartlang-testcase:///foo.dart";
 
 
diff --git a/pkg/front_end/testcases/rasta/export.dart.strong.transformed.expect b/pkg/front_end/testcases/rasta/export.dart.strong.transformed.expect
index b0410f4..6eb1e47 100644
--- a/pkg/front_end/testcases/rasta/export.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/rasta/export.dart.strong.transformed.expect
@@ -3,7 +3,6 @@
 import "foo.dart" as foo;
 additionalExports = (foo::foo)
 
-
 export "org-dartlang-testcase:///foo.dart";
 
 
diff --git a/pkg/front_end/testcases/rasta/generic_factory.dart.outline.expect b/pkg/front_end/testcases/rasta/generic_factory.dart.outline.expect
index 3938bc8..f432c70 100644
--- a/pkg/front_end/testcases/rasta/generic_factory.dart.outline.expect
+++ b/pkg/front_end/testcases/rasta/generic_factory.dart.outline.expect
@@ -6,9 +6,9 @@
 //   factory A.c() = Missing;
 //                   ^
 //
-// pkg/front_end/testcases/rasta/generic_factory.dart:16:11: Error: Redirection constructor target not found: 'Missing'
+// pkg/front_end/testcases/rasta/generic_factory.dart:16:19: Error: Redirection constructor target not found: 'Missing'
 //   factory A.c() = Missing;
-//           ^
+//                   ^
 //
 // pkg/front_end/testcases/rasta/generic_factory.dart:15:19: Error: The constructor function type 'B<C1> Function()' isn't a subtype of 'A<T> Function()'.
 //  - 'B' is from 'pkg/front_end/testcases/rasta/generic_factory.dart'.
diff --git a/pkg/front_end/testcases/rasta/generic_factory.dart.strong.expect b/pkg/front_end/testcases/rasta/generic_factory.dart.strong.expect
index b712837..14a91eb 100644
--- a/pkg/front_end/testcases/rasta/generic_factory.dart.strong.expect
+++ b/pkg/front_end/testcases/rasta/generic_factory.dart.strong.expect
@@ -6,9 +6,9 @@
 //   factory A.c() = Missing;
 //                   ^
 //
-// pkg/front_end/testcases/rasta/generic_factory.dart:16:11: Error: Redirection constructor target not found: 'Missing'
+// pkg/front_end/testcases/rasta/generic_factory.dart:16:19: Error: Redirection constructor target not found: 'Missing'
 //   factory A.c() = Missing;
-//           ^
+//                   ^
 //
 // pkg/front_end/testcases/rasta/generic_factory.dart:15:19: Error: The constructor function type 'B<C1> Function()' isn't a subtype of 'A<T> Function()'.
 //  - 'B' is from 'pkg/front_end/testcases/rasta/generic_factory.dart'.
@@ -24,10 +24,6 @@
 //   factory B.b() = C<C2>;
 //                   ^
 //
-// pkg/front_end/testcases/rasta/generic_factory.dart:16:11: Error: Method not found: 'Missing'.
-//   factory A.c() = Missing;
-//           ^^^^^^^
-//
 import self as self;
 import "dart:core" as core;
 
@@ -78,7 +74,7 @@
   new self::C::•<self::C1*>();
   new self::C::•<self::C3*>();
   new self::C::•<self::C2*>();
-  invalid-expression "pkg/front_end/testcases/rasta/generic_factory.dart:16:11: Error: Method not found: 'Missing'.
-  factory A.c() = Missing;
-          ^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/rasta/generic_factory.dart:35:7: Error: Method not found: 'Missing'.
+  new A<C3>.c();
+      ^";
 }
diff --git a/pkg/front_end/testcases/rasta/generic_factory.dart.strong.transformed.expect b/pkg/front_end/testcases/rasta/generic_factory.dart.strong.transformed.expect
index d362a24..aaef681 100644
--- a/pkg/front_end/testcases/rasta/generic_factory.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/rasta/generic_factory.dart.strong.transformed.expect
@@ -6,9 +6,9 @@
 //   factory A.c() = Missing;
 //                   ^
 //
-// pkg/front_end/testcases/rasta/generic_factory.dart:16:11: Error: Redirection constructor target not found: 'Missing'
+// pkg/front_end/testcases/rasta/generic_factory.dart:16:19: Error: Redirection constructor target not found: 'Missing'
 //   factory A.c() = Missing;
-//           ^
+//                   ^
 //
 // pkg/front_end/testcases/rasta/generic_factory.dart:15:19: Error: The constructor function type 'B<C1> Function()' isn't a subtype of 'A<T> Function()'.
 //  - 'B' is from 'pkg/front_end/testcases/rasta/generic_factory.dart'.
@@ -24,10 +24,6 @@
 //   factory B.b() = C<C2>;
 //                   ^
 //
-// pkg/front_end/testcases/rasta/generic_factory.dart:16:11: Error: Method not found: 'Missing'.
-//   factory A.c() = Missing;
-//           ^^^^^^^
-//
 import self as self;
 import "dart:core" as core;
 
@@ -78,7 +74,7 @@
   new self::C::•<self::C1*>();
   new self::C::•<self::C3*>();
   new self::C::•<self::C2*>();
-  invalid-expression "pkg/front_end/testcases/rasta/generic_factory.dart:16:11: Error: Method not found: 'Missing'.
-  factory A.c() = Missing;
-          ^^^^^^^";
+  invalid-expression "pkg/front_end/testcases/rasta/generic_factory.dart:35:7: Error: Method not found: 'Missing'.
+  new A<C3>.c();
+      ^";
 }
diff --git a/pkg/front_end/testcases/rasta/import_export.dart.outline.expect b/pkg/front_end/testcases/rasta/import_export.dart.outline.expect
index 42bbbc3..13347c0 100644
--- a/pkg/front_end/testcases/rasta/import_export.dart.outline.expect
+++ b/pkg/front_end/testcases/rasta/import_export.dart.outline.expect
@@ -11,7 +11,6 @@
 import "foo.dart" as foo;
 additionalExports = (foo::foo)
 
-
 export "org-dartlang-testcase:///foo.dart";
 
 
diff --git a/pkg/front_end/testcases/rasta/import_export.dart.strong.expect b/pkg/front_end/testcases/rasta/import_export.dart.strong.expect
index e4794e6..18b095f 100644
--- a/pkg/front_end/testcases/rasta/import_export.dart.strong.expect
+++ b/pkg/front_end/testcases/rasta/import_export.dart.strong.expect
@@ -13,7 +13,6 @@
 import "foo.dart" as foo;
 additionalExports = (foo::foo)
 
-
 export "org-dartlang-testcase:///foo.dart";
 
 
diff --git a/pkg/front_end/testcases/rasta/import_export.dart.strong.transformed.expect b/pkg/front_end/testcases/rasta/import_export.dart.strong.transformed.expect
index e4794e6..18b095f 100644
--- a/pkg/front_end/testcases/rasta/import_export.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/rasta/import_export.dart.strong.transformed.expect
@@ -13,7 +13,6 @@
 import "foo.dart" as foo;
 additionalExports = (foo::foo)
 
-
 export "org-dartlang-testcase:///foo.dart";
 
 
diff --git a/pkg/front_end/testcases/rasta/unresolved_constructor.dart.strong.expect b/pkg/front_end/testcases/rasta/unresolved_constructor.dart.strong.expect
index 2a5dbf9..c403f6d 100644
--- a/pkg/front_end/testcases/rasta/unresolved_constructor.dart.strong.expect
+++ b/pkg/front_end/testcases/rasta/unresolved_constructor.dart.strong.expect
@@ -7,7 +7,7 @@
 //          ^
 // pkg/front_end/testcases/rasta/unresolved_constructor.dart:6:3: Context: Found this candidate, but the arguments don't match.
 //   Foo(x, y);
-//   ^
+//   ^^^
 //
 // pkg/front_end/testcases/rasta/unresolved_constructor.dart:11:11: Error: Method not found: 'Foo.notHere'.
 //   new Foo.notHere();
diff --git a/pkg/front_end/testcases/rasta/unresolved_constructor.dart.strong.transformed.expect b/pkg/front_end/testcases/rasta/unresolved_constructor.dart.strong.transformed.expect
index 2a5dbf9..c403f6d 100644
--- a/pkg/front_end/testcases/rasta/unresolved_constructor.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/rasta/unresolved_constructor.dart.strong.transformed.expect
@@ -7,7 +7,7 @@
 //          ^
 // pkg/front_end/testcases/rasta/unresolved_constructor.dart:6:3: Context: Found this candidate, but the arguments don't match.
 //   Foo(x, y);
-//   ^
+//   ^^^
 //
 // pkg/front_end/testcases/rasta/unresolved_constructor.dart:11:11: Error: Method not found: 'Foo.notHere'.
 //   new Foo.notHere();
diff --git a/pkg/front_end/testcases/regress/issue_31299.dart.strong.expect b/pkg/front_end/testcases/regress/issue_31299.dart.strong.expect
index 1c5c821..f7a19ab 100644
--- a/pkg/front_end/testcases/regress/issue_31299.dart.strong.expect
+++ b/pkg/front_end/testcases/regress/issue_31299.dart.strong.expect
@@ -8,7 +8,7 @@
 //            ^
 // pkg/front_end/testcases/regress/issue_31299.dart:10:3: Context: Found this candidate, but the arguments don't match.
 //   A.foo() : m = 2;
-//   ^^^
+//   ^^^^^
 //
 // pkg/front_end/testcases/regress/issue_31299.dart:15:14: Error: Too few positional arguments: 2 required, 0 given.
 //   new A().foo();
diff --git a/pkg/front_end/testcases/regress/issue_35220.dart b/pkg/front_end/testcases/regress/issue_35220.dart
new file mode 100644
index 0000000..93b8134
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_35220.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.md file.
+
+class A {
+  A bad() { return true != 2; }
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/regress/issue_35220.dart.outline.expect b/pkg/front_end/testcases/regress/issue_35220.dart.outline.expect
new file mode 100644
index 0000000..d6c6ea0
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_35220.dart.outline.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    ;
+  method bad() → self::A*
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/regress/issue_35220.dart.strong.expect b/pkg/front_end/testcases/regress/issue_35220.dart.strong.expect
new file mode 100644
index 0000000..09cecc2
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_35220.dart.strong.expect
@@ -0,0 +1,24 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/regress/issue_35220.dart:6:25: Error: A value of type 'bool' can't be assigned to a variable of type 'A'.
+//  - 'A' is from 'pkg/front_end/testcases/regress/issue_35220.dart'.
+//   A bad() { return true != 2; }
+//                         ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    : super core::Object::•()
+    ;
+  method bad() → self::A* {
+    return let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/regress/issue_35220.dart:6:25: Error: A value of type 'bool' can't be assigned to a variable of type 'A'.
+ - 'A' is from 'pkg/front_end/testcases/regress/issue_35220.dart'.
+  A bad() { return true != 2; }
+                        ^" in !true.{core::Object::==}(2) as{TypeError} self::A*;
+  }
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/regress/issue_35220.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_35220.dart.strong.transformed.expect
new file mode 100644
index 0000000..09cecc2
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_35220.dart.strong.transformed.expect
@@ -0,0 +1,24 @@
+library;
+//
+// Problems in library:
+//
+// pkg/front_end/testcases/regress/issue_35220.dart:6:25: Error: A value of type 'bool' can't be assigned to a variable of type 'A'.
+//  - 'A' is from 'pkg/front_end/testcases/regress/issue_35220.dart'.
+//   A bad() { return true != 2; }
+//                         ^
+//
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A*
+    : super core::Object::•()
+    ;
+  method bad() → self::A* {
+    return let final<BottomType> #t1 = invalid-expression "pkg/front_end/testcases/regress/issue_35220.dart:6:25: Error: A value of type 'bool' can't be assigned to a variable of type 'A'.
+ - 'A' is from 'pkg/front_end/testcases/regress/issue_35220.dart'.
+  A bad() { return true != 2; }
+                        ^" in !true.{core::Object::==}(2) as{TypeError} self::A*;
+  }
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/regress/issue_35259.dart.outline.expect b/pkg/front_end/testcases/regress/issue_35259.dart.outline.expect
index 83a6c1d..f18e210 100644
--- a/pkg/front_end/testcases/regress/issue_35259.dart.outline.expect
+++ b/pkg/front_end/testcases/regress/issue_35259.dart.outline.expect
@@ -17,13 +17,13 @@
 //   factory Supertype() = Unresolved;
 //                         ^
 //
-// pkg/front_end/testcases/regress/issue_35259.dart:7:11: Error: Redirection constructor target not found: 'Unresolved'
+// pkg/front_end/testcases/regress/issue_35259.dart:7:25: Error: Redirection constructor target not found: 'Unresolved'
 //   factory Supertype() = Unresolved;
-//           ^
+//                         ^
 //
-// pkg/front_end/testcases/regress/issue_35259.dart:6:11: Error: Redirection constructor target not found: 'Unresolved'
+// pkg/front_end/testcases/regress/issue_35259.dart:6:25: Error: Redirection constructor target not found: 'Unresolved'
 //   factory Supertype() = Unresolved;
-//           ^
+//                         ^
 //
 import self as self;
 import "dart:core" as core;
diff --git a/pkg/front_end/testcases/regress/issue_35259.dart.strong.expect b/pkg/front_end/testcases/regress/issue_35259.dart.strong.expect
index 56694a5..3324103 100644
--- a/pkg/front_end/testcases/regress/issue_35259.dart.strong.expect
+++ b/pkg/front_end/testcases/regress/issue_35259.dart.strong.expect
@@ -17,13 +17,13 @@
 //   factory Supertype() = Unresolved;
 //                         ^
 //
-// pkg/front_end/testcases/regress/issue_35259.dart:7:11: Error: Redirection constructor target not found: 'Unresolved'
+// pkg/front_end/testcases/regress/issue_35259.dart:7:25: Error: Redirection constructor target not found: 'Unresolved'
 //   factory Supertype() = Unresolved;
-//           ^
+//                         ^
 //
-// pkg/front_end/testcases/regress/issue_35259.dart:6:11: Error: Redirection constructor target not found: 'Unresolved'
+// pkg/front_end/testcases/regress/issue_35259.dart:6:25: Error: Redirection constructor target not found: 'Unresolved'
 //   factory Supertype() = Unresolved;
-//           ^
+//                         ^
 //
 // pkg/front_end/testcases/regress/issue_35259.dart:11:13: Error: Can't use 'Supertype' because it is declared more than once.
 //   print(new Supertype());
diff --git a/pkg/front_end/testcases/regress/issue_35259.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_35259.dart.strong.transformed.expect
index 3d6ee63..fb66fb9 100644
--- a/pkg/front_end/testcases/regress/issue_35259.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_35259.dart.strong.transformed.expect
@@ -17,13 +17,13 @@
 //   factory Supertype() = Unresolved;
 //                         ^
 //
-// pkg/front_end/testcases/regress/issue_35259.dart:7:11: Error: Redirection constructor target not found: 'Unresolved'
+// pkg/front_end/testcases/regress/issue_35259.dart:7:25: Error: Redirection constructor target not found: 'Unresolved'
 //   factory Supertype() = Unresolved;
-//           ^
+//                         ^
 //
-// pkg/front_end/testcases/regress/issue_35259.dart:6:11: Error: Redirection constructor target not found: 'Unresolved'
+// pkg/front_end/testcases/regress/issue_35259.dart:6:25: Error: Redirection constructor target not found: 'Unresolved'
 //   factory Supertype() = Unresolved;
-//           ^
+//                         ^
 //
 // pkg/front_end/testcases/regress/issue_35259.dart:11:13: Error: Can't use 'Supertype' because it is declared more than once.
 //   print(new Supertype());
diff --git a/pkg/front_end/testcases/regress/issue_35266.dart.outline.expect b/pkg/front_end/testcases/regress/issue_35266.dart.outline.expect
index 1c17a6b..891e87e 100644
--- a/pkg/front_end/testcases/regress/issue_35266.dart.outline.expect
+++ b/pkg/front_end/testcases/regress/issue_35266.dart.outline.expect
@@ -9,9 +9,9 @@
 //   factory B.foo() = B<T>;
 //           ^^^^^
 //
-// pkg/front_end/testcases/regress/issue_35266.dart:13:11: Error: Can't use 'B.foo' because it is declared more than once.
+// pkg/front_end/testcases/regress/issue_35266.dart:13:21: Error: Can't use 'B.foo' because it is declared more than once.
 //   factory C.bar() = B<K>.foo;
-//           ^
+//                     ^
 //
 import self as self;
 import "dart:core" as core;
diff --git a/pkg/front_end/testcases/regress/issue_35266.dart.strong.expect b/pkg/front_end/testcases/regress/issue_35266.dart.strong.expect
index 6a17040..34845fc 100644
--- a/pkg/front_end/testcases/regress/issue_35266.dart.strong.expect
+++ b/pkg/front_end/testcases/regress/issue_35266.dart.strong.expect
@@ -9,13 +9,9 @@
 //   factory B.foo() = B<T>;
 //           ^^^^^
 //
-// pkg/front_end/testcases/regress/issue_35266.dart:13:11: Error: Can't use 'B.foo' because it is declared more than once.
+// pkg/front_end/testcases/regress/issue_35266.dart:13:21: Error: Can't use 'B.foo' because it is declared more than once.
 //   factory C.bar() = B<K>.foo;
-//           ^
-//
-// pkg/front_end/testcases/regress/issue_35266.dart:13:11: Error: Method not found: 'B.foo'.
-//   factory C.bar() = B<K>.foo;
-//           ^^^
+//                     ^
 //
 import self as self;
 import "dart:core" as core;
@@ -37,7 +33,7 @@
     let dynamic #redirecting_factory = "B.foo" in invalid-expression;
 }
 static method main() → dynamic {
-  invalid-expression "pkg/front_end/testcases/regress/issue_35266.dart:13:11: Error: Method not found: 'B.foo'.
-  factory C.bar() = B<K>.foo;
-          ^^^";
+  invalid-expression "pkg/front_end/testcases/regress/issue_35266.dart:17:7: Error: Method not found: 'B.foo'.
+  new C.bar();
+      ^";
 }
diff --git a/pkg/front_end/testcases/regress/issue_35266.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_35266.dart.strong.transformed.expect
index 1ec6209..a04dc8d 100644
--- a/pkg/front_end/testcases/regress/issue_35266.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_35266.dart.strong.transformed.expect
@@ -9,13 +9,9 @@
 //   factory B.foo() = B<T>;
 //           ^^^^^
 //
-// pkg/front_end/testcases/regress/issue_35266.dart:13:11: Error: Can't use 'B.foo' because it is declared more than once.
+// pkg/front_end/testcases/regress/issue_35266.dart:13:21: Error: Can't use 'B.foo' because it is declared more than once.
 //   factory C.bar() = B<K>.foo;
-//           ^
-//
-// pkg/front_end/testcases/regress/issue_35266.dart:13:11: Error: Method not found: 'B.foo'.
-//   factory C.bar() = B<K>.foo;
-//           ^^^
+//                     ^
 //
 import self as self;
 import "dart:core" as core;
@@ -37,7 +33,7 @@
     let core::String* #redirecting_factory = "B.foo" in invalid-expression;
 }
 static method main() → dynamic {
-  invalid-expression "pkg/front_end/testcases/regress/issue_35266.dart:13:11: Error: Method not found: 'B.foo'.
-  factory C.bar() = B<K>.foo;
-          ^^^";
+  invalid-expression "pkg/front_end/testcases/regress/issue_35266.dart:17:7: Error: Method not found: 'B.foo'.
+  new C.bar();
+      ^";
 }
diff --git a/pkg/front_end/testcases/regress/issue_36647.dart.outline.expect b/pkg/front_end/testcases/regress/issue_36647.dart.outline.expect
index 47f8846..7bf2f7d 100644
--- a/pkg/front_end/testcases/regress/issue_36647.dart.outline.expect
+++ b/pkg/front_end/testcases/regress/issue_36647.dart.outline.expect
@@ -7,10 +7,9 @@
 library;
 import self as self2;
 import "issue_36647_lib2.dart" as iss;
-additionalExports = (iss::xxx)
-, iss::XXX)
-, iss::extends)
-
+additionalExports = (iss::xxx,
+  iss::XXX,
+  iss::extends)
 
 export "org-dartlang-testcase:///issue_36647_lib2.dart";
 
diff --git a/pkg/front_end/testcases/regress/issue_36647.dart.strong.expect b/pkg/front_end/testcases/regress/issue_36647.dart.strong.expect
index 1b4838c..d3285d6 100644
--- a/pkg/front_end/testcases/regress/issue_36647.dart.strong.expect
+++ b/pkg/front_end/testcases/regress/issue_36647.dart.strong.expect
@@ -7,10 +7,9 @@
 library;
 import self as self2;
 import "issue_36647_lib2.dart" as iss;
-additionalExports = (iss::xxx)
-, iss::XXX)
-, iss::extends)
-
+additionalExports = (iss::xxx,
+  iss::XXX,
+  iss::extends)
 
 export "org-dartlang-testcase:///issue_36647_lib2.dart";
 
diff --git a/pkg/front_end/testcases/regress/issue_36647.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_36647.dart.strong.transformed.expect
index 1b4838c..d3285d6 100644
--- a/pkg/front_end/testcases/regress/issue_36647.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_36647.dart.strong.transformed.expect
@@ -7,10 +7,9 @@
 library;
 import self as self2;
 import "issue_36647_lib2.dart" as iss;
-additionalExports = (iss::xxx)
-, iss::XXX)
-, iss::extends)
-
+additionalExports = (iss::xxx,
+  iss::XXX,
+  iss::extends)
 
 export "org-dartlang-testcase:///issue_36647_lib2.dart";
 
diff --git a/pkg/front_end/testcases/regress/issue_36647_2.dart.outline.expect b/pkg/front_end/testcases/regress/issue_36647_2.dart.outline.expect
index 8311ba7..eddabae 100644
--- a/pkg/front_end/testcases/regress/issue_36647_2.dart.outline.expect
+++ b/pkg/front_end/testcases/regress/issue_36647_2.dart.outline.expect
@@ -1,10 +1,9 @@
 library;
 import self as self;
 import "issue_36647_2_lib1.dart" as iss;
-additionalExports = (iss::foo)
-, iss::bar)
-, iss::baz)
-
+additionalExports = (iss::foo,
+  iss::bar,
+  iss::baz)
 
 export "org-dartlang-testcase:///issue_36647_2_lib1.dart";
 
diff --git a/pkg/front_end/testcases/regress/issue_36647_2.dart.strong.expect b/pkg/front_end/testcases/regress/issue_36647_2.dart.strong.expect
index ec50b22..5180e18 100644
--- a/pkg/front_end/testcases/regress/issue_36647_2.dart.strong.expect
+++ b/pkg/front_end/testcases/regress/issue_36647_2.dart.strong.expect
@@ -1,10 +1,9 @@
 library;
 import self as self;
 import "issue_36647_2_lib1.dart" as iss;
-additionalExports = (iss::foo)
-, iss::bar)
-, iss::baz)
-
+additionalExports = (iss::foo,
+  iss::bar,
+  iss::baz)
 
 export "org-dartlang-testcase:///issue_36647_2_lib1.dart";
 
diff --git a/pkg/front_end/testcases/regress/issue_36647_2.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_36647_2.dart.strong.transformed.expect
index ec50b22..5180e18 100644
--- a/pkg/front_end/testcases/regress/issue_36647_2.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/regress/issue_36647_2.dart.strong.transformed.expect
@@ -1,10 +1,9 @@
 library;
 import self as self;
 import "issue_36647_2_lib1.dart" as iss;
-additionalExports = (iss::foo)
-, iss::bar)
-, iss::baz)
-
+additionalExports = (iss::foo,
+  iss::bar,
+  iss::baz)
 
 export "org-dartlang-testcase:///issue_36647_2_lib1.dart";
 
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index e02ba42..34ef1fc 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -20,6 +20,7 @@
 general/bug31124: RuntimeError # Test has no main method (and we shouldn't add one).
 general/bug32629: InstrumentationMismatch # Test has an intentional error
 general/call: TypeCheckError
+general/candidate_found: TypeCheckError
 general/cascade: RuntimeError
 general/constructor_initializer_invalid: RuntimeError # Fails execution after recovery
 general/covariant_generic: RuntimeError
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index bed5b80..c15719f 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -41,6 +41,12 @@
 extensions/internal_resolution: TextSerializationFailure
 extensions/invalid_explicit_access: TextSerializationFailure
 extensions/invalid_explicit_static_access: TextSerializationFailure
+extensions/issue38600: TextSerializationFailure
+extensions/issue38712: TextSerializationFailure
+extensions/issue38713: TextSerializationFailure
+extensions/issue38745: TextSerializationFailure
+extensions/issue38750: TextSerializationFailure
+extensions/issue38755: TextSerializationFailure
 extensions/nested_on_types: TextSerializationFailure
 extensions/null_aware: TextSerializationFailure
 extensions/on_function_type: TextSerializationFailure
@@ -48,6 +54,7 @@
 extensions/on_type_variable_inference: TextSerializationFailure
 extensions/operators: TextSerializationFailure
 extensions/other_kinds: TextSerializationFailure
+extensions/private_members: TextSerializationFailure
 extensions/static_access: TextSerializationFailure
 extensions/static_access_of_instance: TextSerializationFailure
 extensions/tear_offs: TextSerializationFailure
@@ -93,6 +100,7 @@
 general/bug35470: TextSerializationFailure # Was: Pass
 general/bug37476: TextSerializationFailure
 general/call: TypeCheckError
+general/candidate_found: TypeCheckError
 general/cascade: TextSerializationFailure # Was: RuntimeError
 general/casts: TextSerializationFailure # Was: Pass
 general/check_deferred_allocation: TextSerializationFailure # Was: Pass
@@ -114,6 +122,7 @@
 general/co19_language_metadata_syntax_t04: TextSerializationFailure # Was: Pass
 general/complex_class_hierarchy: TextSerializationFailure
 general/compound_binary_implicit_as: TextSerializationFailure
+general/const_redirect_to_nonconst: TextSerializationFailure
 general/constructor_const_inference: TextSerializationFailure # Was: Pass
 general/constructor_cycle: TextSerializationFailure # Was: Pass
 general/constructor_function_types: TextSerializationFailure # Was: Pass
@@ -187,6 +196,7 @@
 general/issue37027: TextSerializationFailure
 general/issue37381: TextSerializationFailure
 general/issue37776: TextSerializationFailure
+general/issue38812: TextSerializationFailure
 general/literals: TextSerializationFailure # Was: Pass
 general/local_generic_function: TextSerializationFailure # Was: Pass
 general/magic_const: TextSerializationFailure # Was: Pass
@@ -242,6 +252,7 @@
 general/prefer_baseclass: TextSerializationFailure # Was: Pass
 general/private_method_tearoff: TextSerializationFailure # Was: Pass
 general/private_method_tearoff_lib: TextSerializationFailure # Was: Pass
+general/promoted_access: TextSerializationFailure
 general/public_method_tearoff: TextSerializationFailure # Was: Pass
 general/public_method_tearoff_lib: TextSerializationFailure # Was: Pass
 general/qualified: TextSerializationFailure # Was: Pass
@@ -864,6 +875,7 @@
 nnbd/intersection_types: TextSerializationFailure
 nnbd/late: TextSerializationFailure
 nnbd/null_check: TextSerializationFailure
+nnbd/nullable_null: TextSerializationFailure
 nnbd/nullable_param: TextSerializationFailure
 nnbd/required: TextSerializationFailure
 nnbd/substitution_in_inference: TextSerializationFailure
@@ -1040,6 +1052,7 @@
 regress/issue_35151: TextSerializationFailure # Was: Pass
 regress/issue_35177: TextSerializationFailure # Was: RuntimeError
 regress/issue_35213: TextSerializationFailure # Was: Pass
+regress/issue_35220: TextSerializationFailure
 regress/issue_35258: TextSerializationFailure # Was: RuntimeError # Expected
 regress/issue_35259: TextSerializationFailure # Was: RuntimeError # Expected
 regress/issue_35260: TextSerializationFailure # Was: RuntimeError # Expected
diff --git a/pkg/front_end/testcases/top_level_variance_test.dart.strong.expect b/pkg/front_end/testcases/top_level_variance_test.dart.strong.expect
index 28ca428..4fcc413 100644
--- a/pkg/front_end/testcases/top_level_variance_test.dart.strong.expect
+++ b/pkg/front_end/testcases/top_level_variance_test.dart.strong.expect
@@ -51,11 +51,11 @@
   <Y extends () →* self::A<dynamic>* = dynamic>() →* void target7 = fsource7;
   (self::A<core::Null?>*) →* dynamic source8;
   <Y extends (self::A<core::Null?>*) →* dynamic = dynamic>() →* void fsource8 = self::toF<(self::A<core::Null?>*) →* dynamic>(source8);
-  <Y extends (self::A<core::Null*>*) →* dynamic = dynamic>() →* void target8 = fsource8;
+  <Y extends (self::A<core::Null?>*) →* dynamic = dynamic>() →* void target8 = fsource8;
   (self::A<dynamic>*) →* self::A<dynamic>* source9;
   () →* (core::Null?) →* dynamic source10;
   <Y extends () →* (core::Null?) →* dynamic = dynamic>() →* void fsource10 = self::toF<() →* (core::Null?) →* dynamic>(source10);
-  <Y extends () →* (core::Null*) →* dynamic = dynamic>() →* void target10 = fsource10;
+  <Y extends () →* (core::Null?) →* dynamic = dynamic>() →* void target10 = fsource10;
   ((dynamic) →* dynamic) →* dynamic source11;
   <Y extends ((dynamic) →* dynamic) →* dynamic = dynamic>() →* void fsource11 = self::toF<((dynamic) →* dynamic) →* dynamic>(source11);
   <Y extends ((dynamic) →* dynamic) →* dynamic = dynamic>() →* void target11 = fsource11;
@@ -87,11 +87,11 @@
   <Y extends self::B<() →* self::A<dynamic>*>* = dynamic>() →* void target7 = fsource7;
   self::B<(self::A<core::Null?>*) →* dynamic>* source8;
   <Y extends self::B<(self::A<core::Null?>*) →* dynamic>* = dynamic>() →* void fsource8 = self::toF<self::B<(self::A<core::Null?>*) →* dynamic>*>(source8);
-  <Y extends self::B<(self::A<core::Null*>*) →* dynamic>* = dynamic>() →* void target8 = fsource8;
+  <Y extends self::B<(self::A<core::Null?>*) →* dynamic>* = dynamic>() →* void target8 = fsource8;
   self::B<(self::A<dynamic>*) →* self::A<dynamic>*>* source9;
   self::B<() →* (core::Null?) →* dynamic>* source10;
   <Y extends self::B<() →* (core::Null?) →* dynamic>* = dynamic>() →* void fsource10 = self::toF<self::B<() →* (core::Null?) →* dynamic>*>(source10);
-  <Y extends self::B<() →* (core::Null*) →* dynamic>* = dynamic>() →* void target10 = fsource10;
+  <Y extends self::B<() →* (core::Null?) →* dynamic>* = dynamic>() →* void target10 = fsource10;
   self::B<((dynamic) →* dynamic) →* dynamic>* source11;
   <Y extends self::B<((dynamic) →* dynamic) →* dynamic>* = dynamic>() →* void fsource11 = self::toF<self::B<((dynamic) →* dynamic) →* dynamic>*>(source11);
   <Y extends self::B<((dynamic) →* dynamic) →* dynamic>* = dynamic>() →* void target11 = fsource11;
diff --git a/pkg/front_end/testcases/top_level_variance_test.dart.strong.transformed.expect b/pkg/front_end/testcases/top_level_variance_test.dart.strong.transformed.expect
index 28ca428..4fcc413 100644
--- a/pkg/front_end/testcases/top_level_variance_test.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/top_level_variance_test.dart.strong.transformed.expect
@@ -51,11 +51,11 @@
   <Y extends () →* self::A<dynamic>* = dynamic>() →* void target7 = fsource7;
   (self::A<core::Null?>*) →* dynamic source8;
   <Y extends (self::A<core::Null?>*) →* dynamic = dynamic>() →* void fsource8 = self::toF<(self::A<core::Null?>*) →* dynamic>(source8);
-  <Y extends (self::A<core::Null*>*) →* dynamic = dynamic>() →* void target8 = fsource8;
+  <Y extends (self::A<core::Null?>*) →* dynamic = dynamic>() →* void target8 = fsource8;
   (self::A<dynamic>*) →* self::A<dynamic>* source9;
   () →* (core::Null?) →* dynamic source10;
   <Y extends () →* (core::Null?) →* dynamic = dynamic>() →* void fsource10 = self::toF<() →* (core::Null?) →* dynamic>(source10);
-  <Y extends () →* (core::Null*) →* dynamic = dynamic>() →* void target10 = fsource10;
+  <Y extends () →* (core::Null?) →* dynamic = dynamic>() →* void target10 = fsource10;
   ((dynamic) →* dynamic) →* dynamic source11;
   <Y extends ((dynamic) →* dynamic) →* dynamic = dynamic>() →* void fsource11 = self::toF<((dynamic) →* dynamic) →* dynamic>(source11);
   <Y extends ((dynamic) →* dynamic) →* dynamic = dynamic>() →* void target11 = fsource11;
@@ -87,11 +87,11 @@
   <Y extends self::B<() →* self::A<dynamic>*>* = dynamic>() →* void target7 = fsource7;
   self::B<(self::A<core::Null?>*) →* dynamic>* source8;
   <Y extends self::B<(self::A<core::Null?>*) →* dynamic>* = dynamic>() →* void fsource8 = self::toF<self::B<(self::A<core::Null?>*) →* dynamic>*>(source8);
-  <Y extends self::B<(self::A<core::Null*>*) →* dynamic>* = dynamic>() →* void target8 = fsource8;
+  <Y extends self::B<(self::A<core::Null?>*) →* dynamic>* = dynamic>() →* void target8 = fsource8;
   self::B<(self::A<dynamic>*) →* self::A<dynamic>*>* source9;
   self::B<() →* (core::Null?) →* dynamic>* source10;
   <Y extends self::B<() →* (core::Null?) →* dynamic>* = dynamic>() →* void fsource10 = self::toF<self::B<() →* (core::Null?) →* dynamic>*>(source10);
-  <Y extends self::B<() →* (core::Null*) →* dynamic>* = dynamic>() →* void target10 = fsource10;
+  <Y extends self::B<() →* (core::Null?) →* dynamic>* = dynamic>() →* void target10 = fsource10;
   self::B<((dynamic) →* dynamic) →* dynamic>* source11;
   <Y extends self::B<((dynamic) →* dynamic) →* dynamic>* = dynamic>() →* void fsource11 = self::toF<self::B<((dynamic) →* dynamic) →* dynamic>*>(source11);
   <Y extends self::B<((dynamic) →* dynamic) →* dynamic>* = dynamic>() →* void target11 = fsource11;
diff --git a/pkg/front_end/testing.json b/pkg/front_end/testing.json
index 5262250..5d80908 100644
--- a/pkg/front_end/testing.json
+++ b/pkg/front_end/testing.json
@@ -390,13 +390,15 @@
     },
     "exclude": [
       "^pkg/analysis_server/lib/src/analysis_server\\.dart",
+      "test/analyser_ignored/",
       "test/extensions/data/",
       "test/id_testing/data/",
       "test/language_versioning/data/",
       "test/flow_analysis/definite_assignment/data/",
       "test/flow_analysis/nullability/data/",
       "test/flow_analysis/reachability/data/",
-      "test/flow_analysis/type_promotion/data/"
+      "test/flow_analysis/type_promotion/data/",
+      "test/patching/data"
     ]
   }
 }
\ No newline at end of file
diff --git a/pkg/front_end/testing_with_lints.json b/pkg/front_end/testing_with_lints.json
index f327807..ed396e1 100644
--- a/pkg/front_end/testing_with_lints.json
+++ b/pkg/front_end/testing_with_lints.json
@@ -11,13 +11,15 @@
     ],
 
     "exclude": [
+      "test/analyser_ignored/",
       "test/extensions/data/",
       "test/id_testing/data/",
       "test/language_versioning/data/",
       "test/flow_analysis/definite_assignment/data/",
       "test/flow_analysis/nullability/data/",
       "test/flow_analysis/reachability/data/",
-      "test/flow_analysis/type_promotion/data/"
+      "test/flow_analysis/type_promotion/data/",
+      "test/patching/data/"
     ]
   }
 }
diff --git a/pkg/front_end/tool/_fasta/command_line.dart b/pkg/front_end/tool/_fasta/command_line.dart
index 619c986..891b2113 100644
--- a/pkg/front_end/tool/_fasta/command_line.dart
+++ b/pkg/front_end/tool/_fasta/command_line.dart
@@ -248,6 +248,7 @@
   "--exclude-source": false,
   "--omit-platform": false,
   "--fatal": ",",
+  "--fatal-skip": String,
   "--help": false,
   // TODO(johnniwinther): Remove legacy option flags. Legacy mode is no longer
   // supported.
@@ -331,6 +332,8 @@
 
   final bool warningsAreFatal = fatal.contains("warnings");
 
+  final int fatalSkip = int.tryParse(options["--fatal-skip"] ?? "0") ?? -1;
+
   final bool bytecode = options["--bytecode"];
 
   final bool compileSdk = options.containsKey("--compile-sdk");
@@ -380,6 +383,7 @@
           ..target = target
           ..throwOnErrorsForDebugging = errorsAreFatal
           ..throwOnWarningsForDebugging = warningsAreFatal
+          ..skipForDebugging = fatalSkip
           ..embedSourceText = !excludeSource
           ..debugDump = dumpIr
           ..omitPlatform = omitPlatform
@@ -436,6 +440,7 @@
     ..target = target
     ..throwOnErrorsForDebugging = errorsAreFatal
     ..throwOnWarningsForDebugging = warningsAreFatal
+    ..skipForDebugging = fatalSkip
     ..embedSourceText = !excludeSource
     ..debugDump = dumpIr
     ..omitPlatform = omitPlatform
diff --git a/pkg/frontend_server/lib/frontend_server.dart b/pkg/frontend_server/lib/frontend_server.dart
index c27f034..c409d5f 100644
--- a/pkg/frontend_server/lib/frontend_server.dart
+++ b/pkg/frontend_server/lib/frontend_server.dart
@@ -9,6 +9,8 @@
 import 'dart:io' hide FileSystemEntity;
 
 import 'package:args/args.dart';
+import 'package:dev_compiler/dev_compiler.dart' show DevCompilerTarget;
+
 // front_end/src imports below that require lint `ignore_for_file`
 // are a temporary state of things until frontend team builds better api
 // that would replace api used below. This api was made private in
@@ -22,6 +24,7 @@
 import 'package:kernel/binary/limited_ast_to_binary.dart';
 import 'package:kernel/kernel.dart'
     show Component, loadComponentSourceFromBytes;
+import 'package:kernel/target/targets.dart' show targets, TargetFlags;
 import 'package:path/path.dart' as path;
 import 'package:usage/uuid/uuid.dart';
 
@@ -34,6 +37,7 @@
 import 'package:vm/incremental_compiler.dart' show IncrementalCompiler;
 import 'package:vm/kernel_front_end.dart'
     show
+        KernelCompilationResults,
         asFileUri,
         compileToKernel,
         convertFileOrUriArgumentToUri,
@@ -46,8 +50,12 @@
         setVMEnvironmentDefines,
         sortComponent,
         writeDepfile;
+import 'package:vm/target/dart_runner.dart' show DartRunnerTarget;
+import 'package:vm/target/flutter.dart' show FlutterTarget;
+import 'package:vm/target/flutter_runner.dart' show FlutterRunnerTarget;
+import 'package:vm/target/vm.dart' show VmTarget;
 
-ArgParser argParser = new ArgParser(allowTrailingOptions: true)
+ArgParser argParser = ArgParser(allowTrailingOptions: true)
   ..addFlag('train',
       help: 'Run through sample command line to produce snapshot',
       negatable: false)
@@ -88,7 +96,13 @@
       help: '.packages file to use for compilation', defaultsTo: null)
   ..addOption('target',
       help: 'Target model that determines what core libraries are available',
-      allowed: <String>['vm', 'flutter', 'flutter_runner', 'dart_runner'],
+      allowed: <String>[
+        'vm',
+        'flutter',
+        'flutter_runner',
+        'dart_runner',
+        'dartdevc'
+      ],
       defaultsTo: 'vm')
   ..addMultiOption('filesystem-root',
       help: 'File path that is used as a root in virtual filesystem used in'
@@ -116,13 +130,21 @@
           ' application, produces better stack traces on exceptions.',
       defaultsTo: true)
   ..addFlag('unsafe-package-serialization',
-      help: 'Potentially unsafe: Does not allow for invalidating packages, '
+      help: '*Deprecated* '
+          'Potentially unsafe: Does not allow for invalidating packages, '
           'additionally the output dill file might include more libraries than '
           'needed. The use case is test-runs, where invalidation is not really '
           'used, and where dill filesize does not matter, and the gain is '
           'improved speed.',
       defaultsTo: false,
       hide: true)
+  ..addFlag('incremental-serialization',
+      help: 'Re-use previously serialized data when serializing. '
+          'The output dill file might include more libraries than strictly '
+          'needed, but the serialization phase will generally be much faster.',
+      defaultsTo: true,
+      negatable: true,
+      hide: true)
   ..addFlag('track-widget-creation',
       help: 'Run a kernel transformer to track creation locations for widgets.',
       defaultsTo: false)
@@ -239,7 +261,7 @@
 class BinaryPrinterFactory {
   /// Creates new [BinaryPrinter] to write to [targetSink].
   BinaryPrinter newBinaryPrinter(Sink<List<int>> targetSink) {
-    return new LimitedBinaryPrinter(targetSink, (_) => true /* predicate */,
+    return LimitedBinaryPrinter(targetSink, (_) => true /* predicate */,
         false /* excludeUriToSource */);
   }
 }
@@ -248,14 +270,23 @@
   FrontendCompiler(this._outputStream,
       {this.printerFactory,
       this.transformer,
-      this.unsafePackageSerialization}) {
+      this.unsafePackageSerialization,
+      this.incrementalSerialization: true}) {
     _outputStream ??= stdout;
-    printerFactory ??= new BinaryPrinterFactory();
+    printerFactory ??= BinaryPrinterFactory();
+    // Initialize supported kernel targets.
+    targets['dart_runner'] = (TargetFlags flags) => DartRunnerTarget(flags);
+    targets['flutter'] = (TargetFlags flags) => FlutterTarget(flags);
+    targets['flutter_runner'] =
+        (TargetFlags flags) => FlutterRunnerTarget(flags);
+    targets['vm'] = (TargetFlags flags) => VmTarget(flags);
+    targets['dartdevc'] = (TargetFlags flags) => DevCompilerTarget(flags);
   }
 
   StringSink _outputStream;
   BinaryPrinterFactory printerFactory;
   bool unsafePackageSerialization;
+  bool incrementalSerialization;
 
   CompilerOptions _compilerOptions;
   BytecodeOptions _bytecodeOptions;
@@ -273,7 +304,7 @@
 
   final ProgramTransformer transformer;
 
-  final List<String> errors = new List<String>();
+  final List<String> errors = List<String>();
 
   @override
   Future<bool> compile(
@@ -293,12 +324,12 @@
     _kernelBinaryFilename = _kernelBinaryFilenameFull;
     _initializeFromDill =
         _options['initialize-from-dill'] ?? _kernelBinaryFilenameFull;
-    final String boundaryKey = new Uuid().generateV4();
+    final String boundaryKey = Uuid().generateV4();
     _outputStream.writeln('result $boundaryKey');
     final Uri sdkRoot = _ensureFolderPath(options['sdk-root']);
     final String platformKernelDill =
         options['platform'] ?? 'platform_strong.dill';
-    final CompilerOptions compilerOptions = new CompilerOptions()
+    final CompilerOptions compilerOptions = CompilerOptions()
       ..sdkRoot = sdkRoot
       ..fileSystem = _fileSystem
       ..packagesFileUri = _getFileOrUri(_options['packages'])
@@ -319,7 +350,6 @@
           case Severity.warning:
             printMessage = true;
             break;
-          case Severity.errorLegacyWarning:
           case Severity.context:
           case Severity.ignored:
             throw 'Unexpected severity: ${message.severity}';
@@ -345,7 +375,7 @@
     }
 
     compilerOptions.bytecode = options['gen-bytecode'];
-    final BytecodeOptions bytecodeOptions = new BytecodeOptions(
+    final BytecodeOptions bytecodeOptions = BytecodeOptions(
         enableAsserts: options['enable-asserts'],
         emitSourceFiles: options['embed-source-text'],
         environmentDefines: environmentDefines)
@@ -363,7 +393,7 @@
     final String importDill = options['import-dill'];
     if (importDill != null) {
       compilerOptions.inputSummaries = <Uri>[
-        Uri.base.resolveUri(new Uri.file(importDill))
+        Uri.base.resolveUri(Uri.file(importDill))
       ];
     }
 
@@ -379,17 +409,23 @@
     _compilerOptions = compilerOptions;
     _bytecodeOptions = bytecodeOptions;
 
-    Component component;
-    Iterable<Uri> compiledSources;
+    KernelCompilationResults results;
+    IncrementalSerializer incrementalSerializer;
     if (options['incremental']) {
       setVMEnvironmentDefines(environmentDefines, _compilerOptions);
 
       _compilerOptions.omitPlatform = false;
-      _generator =
-          generator ?? _createGenerator(new Uri.file(_initializeFromDill));
+      _generator = generator ?? _createGenerator(Uri.file(_initializeFromDill));
       await invalidateIfInitializingFromDill();
-      component = await _runWithPrintRedirection(() => _generator.compile());
-      compiledSources = component.uriToSource.keys;
+      Component component =
+          await _runWithPrintRedirection(() => _generator.compile());
+      results = KernelCompilationResults(
+          component,
+          _generator.getClassHierarchy(),
+          _generator.getCoreTypes(),
+          component.uriToSource.keys);
+
+      incrementalSerializer = _generator.incrementalSerializer;
     } else {
       if (options['link-platform']) {
         // TODO(aam): Remove linkedDependencies once platform is directly embedded
@@ -399,30 +435,29 @@
         ];
       }
       // No bytecode at this step. Bytecode is generated later in _writePackage.
-      final results = await _runWithPrintRedirection(() => compileToKernel(
+      results = await _runWithPrintRedirection(() => compileToKernel(
           _mainSource, compilerOptions,
           aot: options['aot'],
           useGlobalTypeFlowAnalysis: options['tfa'],
           environmentDefines: environmentDefines,
           useProtobufTreeShaker: options['protobuf-tree-shaker']));
-      component = results.component;
-      compiledSources = results.compiledSources;
     }
-    if (component != null) {
+    if (results.component != null) {
       if (transformer != null) {
-        transformer.transform(component);
+        transformer.transform(results.component);
       }
 
-      await writeDillFile(component, _kernelBinaryFilename,
-          filterExternal: importDill != null);
+      await writeDillFile(results, _kernelBinaryFilename,
+          filterExternal: importDill != null,
+          incrementalSerializer: incrementalSerializer);
 
       _outputStream.writeln(boundaryKey);
-      await _outputDependenciesDelta(compiledSources);
+      await _outputDependenciesDelta(results.compiledSources);
       _outputStream
           .writeln('$boundaryKey $_kernelBinaryFilename ${errors.length}');
       final String depfile = options['depfile'];
       if (depfile != null) {
-        await writeDepfile(compilerOptions.fileSystem, compiledSources,
+        await writeDepfile(compilerOptions.fileSystem, results.compiledSources,
             _kernelBinaryFilename, depfile);
       }
 
@@ -449,7 +484,7 @@
   }
 
   void _outputDependenciesDelta(Iterable<Uri> compiledSources) async {
-    Set<Uri> uris = new Set<Uri>();
+    Set<Uri> uris = Set<Uri>();
     for (Uri uri in compiledSources) {
       // Skip empty or corelib dependencies.
       if (uri == null || uri.scheme == 'org-dartlang-sdk') continue;
@@ -478,8 +513,10 @@
     previouslyReportedDependencies = uris;
   }
 
-  writeDillFile(Component component, String filename,
-      {bool filterExternal: false}) async {
+  writeDillFile(KernelCompilationResults results, String filename,
+      {bool filterExternal: false,
+      IncrementalSerializer incrementalSerializer}) async {
+    final Component component = results.component;
     // Remove the cache that came either from this function or from
     // initializing from a kernel file.
     component.metadata.remove(BinaryCacheMetadataRepository.repositoryTag);
@@ -487,16 +524,16 @@
     if (_compilerOptions.bytecode) {
       {
         // Generate bytecode as the output proper.
-        final IOSink sink = new File(filename).openWrite();
+        final IOSink sink = File(filename).openWrite();
         await runWithFrontEndCompilerContext(
             _mainSource, _compilerOptions, component, () async {
           if (_options['incremental']) {
             await forEachPackage(component,
                 (String package, List<Library> libraries) async {
-              _writePackage(component, package, libraries, sink);
+              _writePackage(results, package, libraries, sink);
             });
           } else {
-            _writePackage(component, 'main', component.libraries, sink);
+            _writePackage(results, 'main', component.libraries, sink);
           }
         });
         await sink.close();
@@ -507,7 +544,7 @@
         // of [filename] so that a later invocation of frontend_server will the
         // same arguments will use this to initialize its incremental kernel
         // compiler.
-        final repository = new BinaryCacheMetadataRepository();
+        final repository = BinaryCacheMetadataRepository();
         component.addMetadataRepository(repository);
         for (var lib in component.libraries) {
           var bytes = BinaryCacheMetadataRepository.lookup(lib);
@@ -516,9 +553,9 @@
           }
         }
 
-        final IOSink sink = new File(_initializeFromDill).openWrite();
+        final IOSink sink = File(_initializeFromDill).openWrite();
         final BinaryPrinter printer = filterExternal
-            ? new LimitedBinaryPrinter(
+            ? LimitedBinaryPrinter(
                 sink, (lib) => !lib.isExternal, true /* excludeUriToSource */)
             : printerFactory.newBinaryPrinter(sink);
 
@@ -529,15 +566,18 @@
       }
     } else {
       // Generate AST as the output proper.
-      final IOSink sink = new File(filename).openWrite();
+      final IOSink sink = File(filename).openWrite();
       final BinaryPrinter printer = filterExternal
-          ? new LimitedBinaryPrinter(
+          ? LimitedBinaryPrinter(
               sink, (lib) => !lib.isExternal, true /* excludeUriToSource */)
           : printerFactory.newBinaryPrinter(sink);
 
       sortComponent(component);
 
-      if (unsafePackageSerialization == true) {
+      if (incrementalSerializer != null) {
+        incrementalSerializer.writePackagesToSinkAndTrimComponent(
+            component, sink);
+      } else if (unsafePackageSerialization == true) {
         writePackagesToSinkAndTrimComponent(component, sink);
       }
 
@@ -553,7 +593,7 @@
     // be invalidated by the normal approach anyway.
     if (_generator.initialized) return null;
 
-    final File f = new File(_initializeFromDill);
+    final File f = File(_initializeFromDill);
     if (!f.existsSync()) return null;
 
     Component component;
@@ -603,7 +643,7 @@
     }
   }
 
-  void _writePackage(Component component, String package,
+  void _writePackage(KernelCompilationResults result, String package,
       List<Library> libraries, IOSink sink) {
     final canCache = libraries.isNotEmpty &&
         _compilerOptions.bytecode &&
@@ -618,7 +658,7 @@
       }
     }
 
-    Component partComponent = component;
+    Component partComponent = result.component;
     if (_compilerOptions.bytecode && errors.isEmpty) {
       generateBytecode(partComponent,
           options: _bytecodeOptions,
@@ -631,8 +671,8 @@
       }
     }
 
-    final byteSink = new ByteSink();
-    final BinaryPrinter printer = new LimitedBinaryPrinter(byteSink,
+    final byteSink = ByteSink();
+    final BinaryPrinter printer = LimitedBinaryPrinter(byteSink,
         (lib) => packageFor(lib) == package, false /* excludeUriToSource */);
     printer.writeComponentFile(partComponent);
 
@@ -645,24 +685,30 @@
 
   @override
   Future<Null> recompileDelta({String entryPoint}) async {
-    final String boundaryKey = new Uuid().generateV4();
+    final String boundaryKey = Uuid().generateV4();
     _outputStream.writeln('result $boundaryKey');
     await invalidateIfInitializingFromDill();
     if (entryPoint != null) {
       _mainSource = _getFileOrUri(entryPoint);
     }
     errors.clear();
-    Component deltaProgram = await _generator.compile(entryPoint: _mainSource);
 
+    Component deltaProgram = await _generator.compile(entryPoint: _mainSource);
     if (deltaProgram != null && transformer != null) {
       transformer.transform(deltaProgram);
     }
-    final compiledSources = deltaProgram.uriToSource.keys;
 
-    await writeDillFile(deltaProgram, _kernelBinaryFilename);
+    KernelCompilationResults results = KernelCompilationResults(
+        deltaProgram,
+        _generator.getClassHierarchy(),
+        _generator.getCoreTypes(),
+        deltaProgram.uriToSource.keys);
+
+    await writeDillFile(results, _kernelBinaryFilename,
+        incrementalSerializer: _generator.incrementalSerializer);
 
     _outputStream.writeln(boundaryKey);
-    await _outputDependenciesDelta(compiledSources);
+    await _outputDependenciesDelta(results.compiledSources);
     _outputStream
         .writeln('$boundaryKey $_kernelBinaryFilename ${errors.length}');
     _kernelBinaryFilename = _kernelBinaryFilenameIncremental;
@@ -676,14 +722,14 @@
       String libraryUri,
       String klass,
       bool isStatic) async {
-    final String boundaryKey = new Uuid().generateV4();
+    final String boundaryKey = Uuid().generateV4();
     _outputStream.writeln('result $boundaryKey');
     Procedure procedure = await _generator.compileExpression(
         expression, definitions, typeDefinitions, libraryUri, klass, isStatic);
     if (procedure != null) {
       Component component = createExpressionEvaluationComponent(procedure);
       component = await _generateBytecodeIfNeeded(component);
-      final IOSink sink = new File(_kernelBinaryFilename).openWrite();
+      final IOSink sink = File(_kernelBinaryFilename).openWrite();
       sink.add(serializeComponent(component));
       await sink.close();
       _outputStream
@@ -696,7 +742,7 @@
 
   @override
   void reportError(String msg) {
-    final String boundaryKey = new Uuid().generateV4();
+    final String boundaryKey = Uuid().generateV4();
     _outputStream.writeln('result $boundaryKey');
     _outputStream.writeln(msg);
     _outputStream.writeln(boundaryKey);
@@ -705,7 +751,7 @@
   /// Map of already serialized dill data. All uris in a serialized component
   /// maps to the same blob of data. Used by
   /// [writePackagesToSinkAndTrimComponent].
-  Map<Uri, List<int>> cachedPackageLibraries = new Map<Uri, List<int>>();
+  Map<Uri, List<int>> cachedPackageLibraries = Map<Uri, List<int>>();
 
   /// Map of dependencies for already serialized dill data.
   /// E.g. if blob1 dependents on blob2, but only using a single file from blob1
@@ -713,14 +759,14 @@
   /// dill file in a weird state that could cause the VM to crash if asked to
   /// forcefully compile everything. Used by
   /// [writePackagesToSinkAndTrimComponent].
-  Map<Uri, List<Uri>> cachedPackageDependencies = new Map<Uri, List<Uri>>();
+  Map<Uri, List<Uri>> cachedPackageDependencies = Map<Uri, List<Uri>>();
 
   writePackagesToSinkAndTrimComponent(
       Component deltaProgram, Sink<List<int>> ioSink) {
     if (deltaProgram == null) return;
 
-    List<Library> packageLibraries = new List<Library>();
-    List<Library> libraries = new List<Library>();
+    List<Library> packageLibraries = List<Library>();
+    List<Library> libraries = List<Library>();
     deltaProgram.computeCanonicalNames();
 
     for (var lib in deltaProgram.libraries) {
@@ -735,8 +781,8 @@
       ..clear()
       ..addAll(libraries);
 
-    Map<String, List<Library>> newPackages = new Map<String, List<Library>>();
-    Set<List<int>> alreadyAdded = new Set<List<int>>();
+    Map<String, List<Library>> newPackages = Map<String, List<Library>>();
+    Set<List<int>> alreadyAdded = Set<List<int>>();
 
     addDataAndDependentData(List<int> data, Uri uri) {
       if (alreadyAdded.add(data)) {
@@ -761,20 +807,20 @@
 
     for (String package in newPackages.keys) {
       List<Library> libraries = newPackages[package];
-      Component singleLibrary = new Component(
+      Component singleLibrary = Component(
           libraries: libraries,
           uriToSource: deltaProgram.uriToSource,
           nameRoot: deltaProgram.root);
-      ByteSink byteSink = new ByteSink();
+      ByteSink byteSink = ByteSink();
       final BinaryPrinter printer = printerFactory.newBinaryPrinter(byteSink);
       printer.writeComponentFile(singleLibrary);
 
       // Record things this package blob dependent on.
-      Set<Uri> libraryUris = new Set<Uri>();
+      Set<Uri> libraryUris = Set<Uri>();
       for (Library lib in libraries) {
         libraryUris.add(lib.fileUri);
       }
-      Set<Uri> deps = new Set<Uri>();
+      Set<Uri> deps = Set<Uri>();
       for (Library lib in libraries) {
         for (LibraryDependency dep in lib.dependencies) {
           Library dependencyLibrary = dep.importedLibraryReference.asLibrary;
@@ -789,7 +835,7 @@
       List<int> data = byteSink.builder.takeBytes();
       for (Library lib in libraries) {
         cachedPackageLibraries[lib.fileUri] = data;
-        cachedPackageDependencies[lib.fileUri] = new List<Uri>.from(deps);
+        cachedPackageDependencies[lib.fileUri] = List<Uri>.from(deps);
       }
       ioSink.add(data);
     }
@@ -803,7 +849,7 @@
   @override
   Future<void> rejectLastDelta() async {
     await _generator.reject();
-    final String boundaryKey = new Uuid().generateV4();
+    final String boundaryKey = Uuid().generateV4();
     _outputStream.writeln('result $boundaryKey');
     _outputStream.writeln(boundaryKey);
   }
@@ -823,12 +869,13 @@
       convertFileOrUriArgumentToUri(_fileSystem, fileOrUri);
 
   IncrementalCompiler _createGenerator(Uri initializeFromDillUri) {
-    return new IncrementalCompiler(_compilerOptions, _mainSource,
-        initializeFromDillUri: initializeFromDillUri);
+    return IncrementalCompiler(_compilerOptions, _mainSource,
+        initializeFromDillUri: initializeFromDillUri,
+        incrementalSerialization: incrementalSerialization);
   }
 
   Uri _ensureFolderPath(String path) {
-    String uriPath = new Uri.file(path).toString();
+    String uriPath = Uri.file(path).toString();
     if (!uriPath.endsWith('/')) {
       uriPath = '$uriPath/';
     }
@@ -838,8 +885,8 @@
   /// Runs the given function [f] in a Zone that redirects all prints into
   /// [_outputStream].
   Future<T> _runWithPrintRedirection<T>(Future<T> f()) {
-    return runZoned(() => new Future<T>(f),
-        zoneSpecification: new ZoneSpecification(
+    return runZoned(() => Future<T>(f),
+        zoneSpecification: ZoneSpecification(
             print: (Zone self, ZoneDelegate parent, Zone zone, String line) =>
                 _outputStream.writeln(line)));
   }
@@ -847,7 +894,7 @@
 
 /// A [Sink] that directly writes data into a byte builder.
 class ByteSink implements Sink<List<int>> {
-  final BytesBuilder builder = new BytesBuilder();
+  final BytesBuilder builder = BytesBuilder();
 
   void add(List<int> data) {
     builder.add(data);
@@ -915,7 +962,7 @@
           // <libraryUri: String>
           // <klass: String>
           // <isStatic: true|false>
-          compileExpressionRequest = new _CompileExpressionRequest();
+          compileExpressionRequest = _CompileExpressionRequest();
           boundaryKey =
               string.substring(COMPILE_EXPRESSION_INSTRUCTION_SPACE.length);
           state = _State.COMPILE_EXPRESSION_EXPRESSION;
@@ -1021,11 +1068,11 @@
         '--output-dill=$outputTrainingDill',
       ];
       if (platform != null) {
-        args.add('--platform=${new Uri.file(platform)}');
+        args.add('--platform=${Uri.file(platform)}');
       }
       options = argParser.parse(args);
       compiler ??=
-          new FrontendCompiler(output, printerFactory: binaryPrinterFactory);
+          FrontendCompiler(output, printerFactory: binaryPrinterFactory);
 
       await compiler.compile(input, options, generator: generator);
       compiler.acceptLastDelta();
@@ -1042,9 +1089,10 @@
     }
   }
 
-  compiler ??= new FrontendCompiler(output,
+  compiler ??= FrontendCompiler(output,
       printerFactory: binaryPrinterFactory,
-      unsafePackageSerialization: options["unsafe-package-serialization"]);
+      unsafePackageSerialization: options["unsafe-package-serialization"],
+      incrementalSerialization: options["incremental-serialization"]);
 
   if (options.rest.isNotEmpty) {
     return await compiler.compile(options.rest[0], options,
@@ -1053,7 +1101,7 @@
         : 254;
   }
 
-  Completer<int> completer = new Completer<int>();
+  Completer<int> completer = Completer<int>();
   listenAndCompile(compiler, input ?? stdin, options, completer,
       generator: generator);
   return completer.future;
diff --git a/pkg/frontend_server/pubspec.yaml b/pkg/frontend_server/pubspec.yaml
index 35e2ecf..17121fe 100644
--- a/pkg/frontend_server/pubspec.yaml
+++ b/pkg/frontend_server/pubspec.yaml
@@ -8,6 +8,8 @@
     path: ../build_integration
   vm:
     path: ../vm
+  dev_compiler:
+    path: ../dev_compiler
   front_end: ^0.1.6
   kernel: ^0.3.6
   args: ^1.4.4
diff --git a/pkg/frontend_server/test/frontend_server_test.dart b/pkg/frontend_server/test/frontend_server_test.dart
index 37df317..7da2336 100644
--- a/pkg/frontend_server/test/frontend_server_test.dart
+++ b/pkg/frontend_server/test/frontend_server_test.dart
@@ -896,6 +896,115 @@
       inputStreamController.close();
     });
 
+    test('incremental-serialization', () async {
+      // Package A.
+      var file = new File('${tempDir.path}/pkgA/a.dart')
+        ..createSync(recursive: true);
+      file.writeAsStringSync("pkgA() {}");
+
+      // Package B.
+      file = new File('${tempDir.path}/pkgB/.packages')
+        ..createSync(recursive: true);
+      file.writeAsStringSync("pkgA: ../pkgA");
+      file = new File('${tempDir.path}/pkgB/a.dart')
+        ..createSync(recursive: true);
+      file.writeAsStringSync("pkgB_a() {}");
+      file = new File('${tempDir.path}/pkgB/b.dart')
+        ..createSync(recursive: true);
+      file.writeAsStringSync("import 'package:pkgA/a.dart';"
+          "pkgB_b() { pkgA(); }");
+
+      // Application.
+      file = new File('${tempDir.path}/app/.packages')
+        ..createSync(recursive: true);
+      file.writeAsStringSync("pkgA:../pkgA\n"
+          "pkgB:../pkgB");
+
+      // Entry point A uses both package A and B.
+      file = new File('${tempDir.path}/app/a.dart')
+        ..createSync(recursive: true);
+      file.writeAsStringSync("import 'package:pkgB/b.dart';"
+          "import 'package:pkgB/a.dart';"
+          "appA() { pkgB_a(); pkgB_b(); }");
+
+      // Entry point B uses only package B.
+      var fileB = new File('${tempDir.path}/app/B.dart')
+        ..createSync(recursive: true);
+      fileB.writeAsStringSync("import 'package:pkgB/a.dart';"
+          "appB() { pkgB_a(); }");
+
+      // Other setup.
+      var dillFile = new File('${tempDir.path}/app.dill');
+      expect(dillFile.existsSync(), equals(false));
+
+      // First compile app entry point A.
+      final List<String> args = <String>[
+        '--sdk-root=${sdkRoot.toFilePath()}',
+        '--incremental',
+        '--platform=${platformKernel.path}',
+        '--output-dill=${dillFile.path}',
+        '--incremental-serialization',
+      ];
+
+      final StreamController<List<int>> inputStreamController =
+          new StreamController<List<int>>();
+      final StreamController<List<int>> stdoutStreamController =
+          new StreamController<List<int>>();
+      final IOSink ioSink = new IOSink(stdoutStreamController.sink);
+      StreamController<Result> receivedResults = new StreamController<Result>();
+      final outputParser = new OutputParser(receivedResults);
+      stdoutStreamController.stream
+          .transform(utf8.decoder)
+          .transform(const LineSplitter())
+          .listen(outputParser.listener);
+
+      Future<int> result =
+          starter(args, input: inputStreamController.stream, output: ioSink);
+      inputStreamController.add('compile ${file.path}\n'.codeUnits);
+      int count = 0;
+      receivedResults.stream.listen((Result compiledResult) {
+        CompilationResult result =
+            new CompilationResult.parse(compiledResult.status);
+        switch (count) {
+          case 0:
+            expect(dillFile.existsSync(), equals(true));
+            expect(result.filename, dillFile.path);
+            expect(result.errorsCount, 0);
+            count += 1;
+            inputStreamController.add('accept\n'.codeUnits);
+            inputStreamController.add('reset\n'.codeUnits);
+
+            inputStreamController.add('recompile ${fileB.path} abc\n'
+                    '${fileB.path}\n'
+                    'abc\n'
+                .codeUnits);
+            break;
+          case 1:
+            expect(result.filename, dillFile.path);
+            expect(result.errorsCount, 0);
+            inputStreamController.add('quit\n'.codeUnits);
+
+            // Loadable.
+            Component component = loadComponentFromBinary(dillFile.path);
+
+            // Contains (at least) the 2 files we want.
+            component.libraries
+                    .where((l) =>
+                        l.importUri.toString() == "package:pkgB/a.dart" ||
+                        l.fileUri.toString().contains(fileB.path))
+                    .length ==
+                2;
+
+            // Verifiable (together with the platform file).
+            component =
+                loadComponentFromBinary(platformKernel.toFilePath(), component);
+            verifyComponent(component);
+        }
+      });
+      expect(await result, 0);
+      inputStreamController.close();
+    });
+
     test('compile and recompile report non-zero error count', () async {
       var file = new File('${tempDir.path}/foo.dart')..createSync();
       file.writeAsStringSync("main() { foo(); bar(); }\n");
diff --git a/pkg/js_ast/lib/src/nodes.dart b/pkg/js_ast/lib/src/nodes.dart
index d2970d4..82cdc4f 100644
--- a/pkg/js_ast/lib/src/nodes.dart
+++ b/pkg/js_ast/lib/src/nodes.dart
@@ -966,6 +966,8 @@
 }
 
 abstract class Expression extends Node {
+  // [precedenceLevel] must not be used before printing, as deferred nodes can
+  // have precedence depending on how the deferred node is resolved.
   int get precedenceLevel;
 
   Statement toStatement() => new ExpressionStatement(this);
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index 333a741..7e503a8 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -143,7 +143,7 @@
 
 type ComponentFile {
   UInt32 magic = 0x90ABCDEF;
-  UInt32 formatVersion = 34;
+  UInt32 formatVersion = 35;
   List<String> problemsAsJson; // Described in problems.md.
   Library[] libraries;
   UriSource sourceMap;
diff --git a/pkg/kernel/doc/nnbd_api.md b/pkg/kernel/doc/nnbd_api.md
index 1c6b8d5..b3e4ec8 100644
--- a/pkg/kernel/doc/nnbd_api.md
+++ b/pkg/kernel/doc/nnbd_api.md
@@ -8,6 +8,12 @@
 
 ## CHANGELOG
 
+2019.10.15:
+- Added information about implementing the subtype relation.
+
+2019.10.15:
+- Added description of `DartType.withNullability`.
+
 2019.09.26:
 - Initial version uploaded.
 
@@ -277,10 +283,18 @@
 
 #### Nullability attribute on types
 
-- `DartType.nullability` is added to `DartType` and the implementations are added to subclasses to subclasses (fields for InterfaceType, FunctionType, TypedefType, and TypeParameterType, concrete getter for `TypeParameterType`).
+- `DartType.nullability` is added to `DartType` and the implementations are added to the subclasses (fields for InterfaceType, FunctionType, TypedefType, and TypeParameterType, concrete getter for `TypeParameterType`).
 - Nullability parameter is added to constructors of InterfaceType, FunctionType, TypedefType, and TypeParameterType.
-- `TypeParameterType.typeParameterTypeNullability is added.  For details see section **Nullability of Intersection Types** of this document.
-- `TypeParameterType.computeNullabilityFromBound is added.
+- `TypeParameterType.typeParameterTypeNullability` is added.  For details see section **Nullability of Intersection Types** of this document.
+- `TypeParameterType.computeNullabilityFromBound` is added.
+- `DartType.withNullability` method is added to `DartType` and is implemented in its subclasses.  The method takes a single parameter, the desired nullability, and returns the type that is the receiver with the given nullability.  If the receiver already has the nullability that is passed in as the parameter, the receiver object itself is returned, and a copy isn't created.  If the types that are represented by a particular `DartType` subclass always have a certain nullability, like `dynamic` or `void`, invocations of `withNullability` on them always return the receiver.
+
+#### Subtype queries
+
+- `SubtypeCheckMode` enum is added.  It has two values corresponding to the two modes for type checks: `SubtypeCheckMode.withNullabilities` corresponds to the mode where the nullability modifiers on the types are taken into the account according to the [specification for the subtype relation](https://github.com/dart-lang/language/blob/master/resources/type-system/subtyping.md), and `SubtypeCheckMode.ignoringNullabilities` corresponds to the mode where the nullability markers are ignored as if the check was made on pre-NNBD types.
+- `SubtypeTester.isSubtypeOf` is updated to receive additional parameter, a `SubtypeCheckMode`.
+- `IsSubtypeOf` class is added.  It represents a result of a nullability-aware type check.  Objects of `IsSubtypeOf` can further be queried for whether the checked types are in the subtype relation when the nullability modifiers are taken into account (using `IsSubtypeOf.isSubtypeWhenUsingNullabilities`) or when the modifiers are ignored (using `IsSubtypeOf.isSubtypeWhenIgnoringNullabilities`).
+- `SubtypeTester.performNullabilityAwareSubtypeCheck` method is added.  It takes two types as input and produces a result of type `IsSubtypeOf`.  Using `SubtypeTester.performNullabilityAwareSubtypeCheck` is recommended for performance considerations if a call site needs to differentiate between NNBD and pre-NNBD cases.
 
 #### isRequired and isLate flags
 
@@ -341,6 +355,18 @@
 
 The code updated this way will generate nullable and non-nullable types as desired for the opted-in libraries and will generate legacy types for the opted-out libraries.  It should also be easy to deprecate the weak-NNBD mode for such code: `Library.nonNullable` and `Library.nullable` will start returning the corresponding nullability constants.
 
+#### Avoiding SubtypeCheckMode.ignoringNullabilities
+
+As described in section **Subtype queries**, `SubtypeTester.isSubtypeOf` now accepts additional parameter, a `SubtypeCheckMode`.  The parameter is required to clearly indicate the mode of checking, and is initially set to `SubtypeCheckMode.ignoringNullabilities` at all call sites within CFE and in the client code.
+
+As a part of implementing the NNBD feature, all such call sites need to take the nullability attributes into account.  In [the weak null checking mode](https://github.com/dart-lang/language/blob/master/accepted/future-releases/nnbd/feature-specification.md#errors-as-warnings) all errors that originate from the NNBD-related changes should be treated as warnings.  For some of the call sites it means that they should differentiate between two situations: whether one type is a subtype of the other type with nullabilities taken into account or only if the nullability modifiers are ignored.
+
+One way to make the differentiation is to invoke `isSubtypeOf` twice.  The first time it is invoked with `SubtypeCheckMode.withNullabilities` as the mode.  If it returns `true`, the subtype check succeeds when the nullability modifiers are taken into account and it would have succeeded also if the modifiers were ignored.  It means that neither warning nor error should be reported if it was dependent on the result of the type check.
+
+If `isSubtypeOf` returns `false` when the mode is `SubtypeCheckMode.withNullabilities`, it is still possible that the check fails only because of the nullability modifiers.  To check if it's true, another invocation of `isSubtypeOf` can be made with `SubtypeCheckMode.ignoringNullabilities` as the third parameter.  If the result is `true`, the subtype check fails only because of the nullability modifiers, and a warning should be reported.  If the result is `false`, the check fails in both modes, and an error should be reported.
+
+To save some computations, a single invocation of `performNullabilityAwareSubtypeCheck` can be made instead of the two invocations of `isSubtypeOf`.  The method takes two types as the input and returns an object of `IsSubtypeOf` as the result.  The return value of the method can further be queried to determine if an error or a warning should be reported.  If invocation of `IsSubtypeOf.isSubtypeWhenUsingNullabilities` returns `true`, the two types are in the subtype relation in both modes, and neither error nor warning should be reported.  If it returns `false`, the failure may be due to the nullability modifiers.  To differentiate between the two possibilities, an invocation of `IsSubtypeOf.isSubtypeWhenIgnoringNullabilities` can be made.  If the result is `true`, a warning should be issued; otherwise, an error should be reported.
+
 #### Computing TypeParameterType.nullability
 
 As described in section **Nullability of Intersection Types**, objects of `TypeParameterType` implement `.nullability` as a getter, not a field, and the overall nullability value for the type is not serialized in the binary format.  The back ends that implement their own deserialization may need to compute the nullability for `TypeParameterType`s.
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index 49f81a9..399b75e 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -322,7 +322,7 @@
       _languageVersionMinor ?? defaultLanguageVersionMinor;
   void setLanguageVersion(int languageVersionMajor, int languageVersionMinor) {
     if (languageVersionMajor == null || languageVersionMinor == null) {
-      throw new StateError("Trying to set langauge version 'null'");
+      throw new StateError("Trying to set language version 'null'");
     }
     _languageVersionMajor = languageVersionMajor;
     _languageVersionMinor = languageVersionMinor;
@@ -2597,7 +2597,9 @@
     }
     var type = getStaticType(types);
     while (type is TypeParameterType) {
-      type = (type as TypeParameterType).parameter.bound;
+      TypeParameterType typeParameterType = type;
+      type =
+          typeParameterType.promotedBound ?? typeParameterType.parameter.bound;
     }
     if (type == types.nullType) {
       return superclass.bottomType;
@@ -6045,6 +6047,30 @@
     return a == b ? covariant : contravariant;
   }
 
+  /// Returns true if [a] is greater than (above) [b] in the partial order
+  /// induced by the variance lattice.
+  static bool greaterThan(int a, int b) {
+    return greaterThanOrEqual(a, b) && a != b;
+  }
+
+  /// Returns true if [a] is greater than (above) or equal to [b] in the
+  /// partial order induced by the variance lattice.
+  static bool greaterThanOrEqual(int a, int b) {
+    return meet(a, b) == b;
+  }
+
+  /// Returns true if [a] is less than (below) [b] in the partial order
+  /// induced by the variance lattice.
+  static bool lessThan(int a, int b) {
+    return lessThanOrEqual(a, b) && a != b;
+  }
+
+  /// Returns true if [a] is less than (below) or equal to [b] in the
+  /// partial order induced by the variance lattice.
+  static bool lessThanOrEqual(int a, int b) {
+    return meet(a, b) == a;
+  }
+
   static int fromString(String variance) {
     if (variance == "in") {
       return contravariant;
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index 4ef7288..dbfb0a4 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -60,6 +60,15 @@
   int componentFileSizeInBytes;
 }
 
+class SubComponentView {
+  final List<Library> libraries;
+  final int componentStartOffset;
+  final int componentFileSize;
+
+  SubComponentView(
+      this.libraries, this.componentStartOffset, this.componentFileSize);
+}
+
 class BinaryBuilder {
   final List<VariableDeclaration> variableStack = <VariableDeclaration>[];
   final List<LabeledStatement> labelStack = <LabeledStatement>[];
@@ -454,8 +463,14 @@
   /// computed ahead of time.
   ///
   /// The input bytes may contain multiple files concatenated.
-  void readComponent(Component component, {bool checkCanonicalNames: false}) {
-    Timeline.timeSync("BinaryBuilder.readComponent", () {
+  ///
+  /// If [createView] is true, returns a list of [SubComponentView] - one for
+  /// each concatenated dill - each of which knowing where in the combined dill
+  /// it came from. If [createView] is false null will be returned.
+  List<SubComponentView> readComponent(Component component,
+      {bool checkCanonicalNames: false, bool createView: false}) {
+    return Timeline.timeSync<List<SubComponentView>>(
+        "BinaryBuilder.readComponent", () {
       _checkEmptyInput();
 
       // Check that we have a .dill file and it has the correct version before we
@@ -476,14 +491,24 @@
         _disableLazyClassReading = true;
       }
       int componentFileIndex = 0;
+      List<SubComponentView> views;
+      if (createView) {
+        views = new List<SubComponentView>();
+      }
       while (_byteOffset < _bytes.length) {
-        _readOneComponent(component, componentFileSizes[componentFileIndex]);
+        SubComponentView view = _readOneComponent(
+            component, componentFileSizes[componentFileIndex],
+            createView: createView);
+        if (createView) {
+          views.add(view);
+        }
         ++componentFileIndex;
       }
 
       if (checkCanonicalNames) {
         _checkCanonicalNameChildren(component.root);
       }
+      return views;
     });
   }
 
@@ -651,7 +676,8 @@
     _byteOffset = _componentStartOffset + componentFileSize;
   }
 
-  void _readOneComponent(Component component, int componentFileSize) {
+  SubComponentView _readOneComponent(Component component, int componentFileSize,
+      {bool createView: false}) {
     _componentStartOffset = _byteOffset;
 
     final int magic = readUint32();
@@ -693,9 +719,19 @@
     readConstantTable();
 
     int numberOfLibraries = index.libraryCount;
+
+    SubComponentView result;
+    if (createView) {
+      result = new SubComponentView(new List<Library>(numberOfLibraries),
+          _componentStartOffset, componentFileSize);
+    }
+
     for (int i = 0; i < numberOfLibraries; ++i) {
       _byteOffset = index.libraryOffsets[i];
-      readLibrary(component, index.libraryOffsets[i + 1]);
+      Library library = readLibrary(component, index.libraryOffsets[i + 1]);
+      if (createView) {
+        result.libraries[i] = library;
+      }
     }
 
     var mainMethod =
@@ -705,6 +741,8 @@
     _byteOffset = _componentStartOffset + componentFileSize;
 
     assert(typeParameterStack.isEmpty);
+
+    return result;
   }
 
   /// Read a list of strings. If the list is empty, [null] is returned.
@@ -956,6 +994,7 @@
   void _readAdditionalExports(Library library) {
     int numExportedReference = readUInt();
     if (numExportedReference != 0) {
+      library.additionalExports.clear();
       for (int i = 0; i < numExportedReference; i++) {
         CanonicalName exportedName = readCanonicalNameReference();
         Reference reference = exportedName.getReference();
@@ -1012,7 +1051,9 @@
     readAndPushTypeParameterList(node.typeParameters, node);
     var type = readDartType();
     readAndPushTypeParameterList(node.typeParametersOfFunctionType, node);
+    node.positionalParameters.clear();
     node.positionalParameters.addAll(readAndPushVariableDeclarationList());
+    node.namedParameters.clear();
     node.namedParameters.addAll(readAndPushVariableDeclarationList());
     typeParameterStack.length = 0;
     variableStack.length = 0;
@@ -1144,17 +1185,20 @@
     }
 
     int length = readUInt();
+    if (shouldWriteData) {
+      node.members.length = length;
+    }
     for (int i = 0; i < length; i++) {
       Name name = readName();
       int kind = readByte();
       int flags = readByte();
       CanonicalName canonicalName = readCanonicalNameReference();
       if (shouldWriteData) {
-        node.members.add(new ExtensionMemberDescriptor(
+        node.members[i] = new ExtensionMemberDescriptor(
             name: name,
             kind: ExtensionMemberKind.values[kind],
             member: canonicalName.getReference())
-          ..flags = flags);
+          ..flags = flags;
       }
     }
     return node;
diff --git a/pkg/kernel/lib/binary/tag.dart b/pkg/kernel/lib/binary/tag.dart
index 1768aae..230688a 100644
--- a/pkg/kernel/lib/binary/tag.dart
+++ b/pkg/kernel/lib/binary/tag.dart
@@ -148,7 +148,7 @@
   /// Internal version of kernel binary format.
   /// Bump it when making incompatible changes in kernel binaries.
   /// Keep in sync with runtime/vm/kernel_binary.h, pkg/kernel/binary.md.
-  static const int BinaryFormatVersion = 34;
+  static const int BinaryFormatVersion = 35;
 }
 
 abstract class ConstantTag {
diff --git a/pkg/kernel/lib/src/bounds_checks.dart b/pkg/kernel/lib/src/bounds_checks.dart
index 363f5e7..d4e2d21 100644
--- a/pkg/kernel/lib/src/bounds_checks.dart
+++ b/pkg/kernel/lib/src/bounds_checks.dart
@@ -113,7 +113,8 @@
 
 DartType instantiateToBounds(DartType type, Class objectClass) {
   if (type is InterfaceType) {
-    for (var typeArgument in type.typeArguments) {
+    if (type.typeArguments.isEmpty) return type;
+    for (DartType typeArgument in type.typeArguments) {
       // If at least one of the arguments is not dynamic, we assume that the
       // type is not raw and does not need instantiation of its type parameters
       // to their bounds.
@@ -121,17 +122,22 @@
         return type;
       }
     }
-    return new InterfaceType.byReference(type.className,
-        calculateBounds(type.classNode.typeParameters, objectClass));
+    return new InterfaceType.byReference(
+        type.className,
+        calculateBounds(type.classNode.typeParameters, objectClass),
+        type.nullability);
   }
   if (type is TypedefType) {
-    for (var typeArgument in type.typeArguments) {
+    if (type.typeArguments.isEmpty) return type;
+    for (DartType typeArgument in type.typeArguments) {
       if (typeArgument is! DynamicType) {
         return type;
       }
     }
-    return new TypedefType.byReference(type.typedefReference,
-        calculateBounds(type.typedefNode.typeParameters, objectClass));
+    return new TypedefType.byReference(
+        type.typedefReference,
+        calculateBounds(type.typedefNode.typeParameters, objectClass),
+        type.nullability);
   }
   return type;
 }
@@ -192,16 +198,20 @@
 }
 
 class TypeArgumentIssue {
-  // The type argument that violated the bound.
+  /// The index for type argument within the passed type arguments.
+  final int index;
+
+  /// The type argument that violated the bound.
   final DartType argument;
 
-  // The type parameter with the bound that was violated.
+  /// The type parameter with the bound that was violated.
   final TypeParameter typeParameter;
 
-  // The enclosing type of the issue, that is, the one with [typeParameter].
+  /// The enclosing type of the issue, that is, the one with [typeParameter].
   final DartType enclosingType;
 
-  TypeArgumentIssue(this.argument, this.typeParameter, this.enclosingType);
+  TypeArgumentIssue(
+      this.index, this.argument, this.typeParameter, this.enclosingType);
 }
 
 // TODO(dmitryas):  Remove [typedefInstantiations] when type arguments passed to
@@ -273,13 +283,13 @@
     if (argument is FunctionType && argument.typeParameters.length > 0) {
       // Generic function types aren't allowed as type arguments either.
       result ??= <TypeArgumentIssue>[];
-      result.add(new TypeArgumentIssue(argument, variables[i], type));
+      result.add(new TypeArgumentIssue(i, argument, variables[i], type));
     } else if (!typeEnvironment.isSubtypeOf(
         argument,
         substitute(variables[i].bound, substitutionMap),
         SubtypeCheckMode.ignoringNullabilities)) {
       result ??= <TypeArgumentIssue>[];
-      result.add(new TypeArgumentIssue(argument, variables[i], type));
+      result.add(new TypeArgumentIssue(i, argument, variables[i], type));
     }
 
     List<TypeArgumentIssue> issues = findTypeArgumentIssues(
@@ -320,15 +330,15 @@
     if (argument is FunctionType && argument.typeParameters.length > 0) {
       // Generic function types aren't allowed as type arguments either.
       result ??= <TypeArgumentIssue>[];
-      result
-          .add(new TypeArgumentIssue(argumentsToReport[i], variables[i], type));
+      result.add(
+          new TypeArgumentIssue(i, argumentsToReport[i], variables[i], type));
     } else if (!typeEnvironment.isSubtypeOf(
         argument,
         substitute(variables[i].bound, substitutionMap),
         SubtypeCheckMode.ignoringNullabilities)) {
       result ??= <TypeArgumentIssue>[];
-      result
-          .add(new TypeArgumentIssue(argumentsToReport[i], variables[i], type));
+      result.add(
+          new TypeArgumentIssue(i, argumentsToReport[i], variables[i], type));
     }
   }
   if (argumentsResult != null) {
@@ -359,17 +369,17 @@
     DartType argument = arguments[i];
     if (argument is TypeParameterType && argument.promotedBound != null) {
       result ??= <TypeArgumentIssue>[];
-      result.add(new TypeArgumentIssue(argument, parameters[i], null));
+      result.add(new TypeArgumentIssue(i, argument, parameters[i], null));
     } else if (argument is FunctionType && argument.typeParameters.length > 0) {
       // Generic function types aren't allowed as type arguments either.
       result ??= <TypeArgumentIssue>[];
-      result.add(new TypeArgumentIssue(argument, parameters[i], null));
+      result.add(new TypeArgumentIssue(i, argument, parameters[i], null));
     } else if (!typeEnvironment.isSubtypeOf(
         argument,
         substitute(parameters[i].bound, substitutionMap),
         SubtypeCheckMode.ignoringNullabilities)) {
       result ??= <TypeArgumentIssue>[];
-      result.add(new TypeArgumentIssue(argument, parameters[i], null));
+      result.add(new TypeArgumentIssue(i, argument, parameters[i], null));
     }
 
     List<TypeArgumentIssue> issues = findTypeArgumentIssues(
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index d3a9b1a..8f6d44e 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.dart
@@ -459,13 +459,8 @@
   void writeAdditionalExports(List<Reference> additionalExports) {
     if (additionalExports.isEmpty) return;
     write('additionalExports = (');
-    bool isFirst = true;
-    for (Reference reference in additionalExports) {
-      if (isFirst) {
-        isFirst = false;
-      } else {
-        write(', ');
-      }
+    for (int i = 0; i < additionalExports.length; i++) {
+      Reference reference = additionalExports[i];
       var node = reference.node;
       if (node is Class) {
         Library nodeLibrary = node.enclosingLibrary;
@@ -488,10 +483,14 @@
       } else {
         throw new UnimplementedError('${node.runtimeType}');
       }
-      endLine(')');
-    }
 
-    endLine();
+      if (i + 1 == additionalExports.length) {
+        endLine(")");
+      } else {
+        endLine(",");
+        write("  ");
+      }
+    }
   }
 
   void writeComponentFile(Component component) {
diff --git a/pkg/kernel/lib/type_environment.dart b/pkg/kernel/lib/type_environment.dart
index b6cfaa3..d872d55 100644
--- a/pkg/kernel/lib/type_environment.dart
+++ b/pkg/kernel/lib/type_environment.dart
@@ -295,10 +295,26 @@
       if (upcastType == null) return const IsSubtypeOf.never();
       for (int i = 0; i < upcastType.typeArguments.length; ++i) {
         // Termination: the 'supertype' parameter decreases in size.
-        if (!performNullabilityAwareSubtypeCheck(
-                upcastType.typeArguments[i], supertype.typeArguments[i])
-            .isSubtypeWhenIgnoringNullabilities()) {
-          return const IsSubtypeOf.never();
+        int variance = upcastType.classNode.typeParameters[i].variance;
+        DartType leftType = upcastType.typeArguments[i];
+        DartType rightType = supertype.typeArguments[i];
+        if (variance == Variance.contravariant) {
+          if (!performNullabilityAwareSubtypeCheck(rightType, leftType)
+              .isSubtypeWhenIgnoringNullabilities()) {
+            return const IsSubtypeOf.never();
+          }
+        } else if (variance == Variance.invariant) {
+          if (!performNullabilityAwareSubtypeCheck(rightType, leftType)
+                  .isSubtypeWhenIgnoringNullabilities() ||
+              !performNullabilityAwareSubtypeCheck(leftType, rightType)
+                  .isSubtypeWhenIgnoringNullabilities()) {
+            return const IsSubtypeOf.never();
+          }
+        } else {
+          if (!performNullabilityAwareSubtypeCheck(leftType, rightType)
+              .isSubtypeWhenIgnoringNullabilities()) {
+            return const IsSubtypeOf.never();
+          }
         }
       }
       return const IsSubtypeOf.always();
diff --git a/pkg/kernel/test/class_hierarchy_test.dart b/pkg/kernel/test/class_hierarchy_test.dart
index c4bdcd8..0d53973 100644
--- a/pkg/kernel/test/class_hierarchy_test.dart
+++ b/pkg/kernel/test/class_hierarchy_test.dart
@@ -293,7 +293,7 @@
 
   Class addClass(Class c) {
     if (_hierarchy != null) {
-      fail('The classs hierarchy has already been created.');
+      fail('The class hierarchy has already been created.');
     }
     library.addClass(c);
     return c;
diff --git a/pkg/kernel/test/round_trip.dart b/pkg/kernel/test/round_trip.dart
index 8269b76..b94ae42 100644
--- a/pkg/kernel/test/round_trip.dart
+++ b/pkg/kernel/test/round_trip.dart
@@ -3,73 +3,63 @@
 // BSD-style license that can be found in the LICENSE file.
 library kernel.round_trip;
 
-import 'dart:async';
 import 'dart:io';
 import 'package:kernel/binary/ast_from_binary.dart';
 import 'package:kernel/binary/ast_to_binary.dart';
 import 'package:kernel/kernel.dart';
 
 const String usage = '''
-Usage: round_trip.dart FILE.dill
+Usage: round_trip.dart FILE.dill [sdk.dill]
 
 Deserialize and serialize the given component and check that the resulting byte
 sequence is identical to the original.
 ''';
 
-void main(List<String> args) {
-  if (args.length != 1) {
+void main(List<String> args) async {
+  if (args.length == 1) {
+    await testRoundTrip(new File(args[0]).readAsBytesSync(), null);
+  } else if (args.length == 2) {
+    await testRoundTrip(new File(args[0]).readAsBytesSync(),
+        new File(args[1]).readAsBytesSync());
+  } else {
     print(usage);
     exit(1);
   }
-  testRoundTrip(new File(args[0]).readAsBytesSync());
 }
 
-void testRoundTrip(List<int> bytes) {
+void testRoundTrip(List<int> bytes, List<int> sdkBytes) async {
   var component = new Component();
+  if (sdkBytes != null) {
+    var sdk = new Component(nameRoot: component.root);
+    new BinaryBuilder(sdkBytes).readSingleFileComponent(sdk);
+  }
   new BinaryBuilder(bytes).readSingleFileComponent(component);
-  new BinaryPrinterWithExpectedOutput(bytes).writeComponentFile(component);
-}
-
-class DummyStreamConsumer extends StreamConsumer<List<int>> {
-  @override
-  Future addStream(Stream<List<int>> stream) async => null;
-
-  @override
-  Future close() async => null;
-}
-
-/// Variant of the binary serializer that compares the output against an
-/// existing buffer.
-///
-/// As opposed to comparing binary files directly, when this fails, the stack
-/// trace shows what the serializer was doing when the output started to differ.
-class BinaryPrinterWithExpectedOutput extends BinaryPrinter {
-  final List<int> expectedBytes;
-  int offset = 0;
-
-  static const int eof = -1;
-
-  BinaryPrinterWithExpectedOutput(this.expectedBytes)
-      : super(new IOSink(new DummyStreamConsumer()));
-
-  String show(int byte) {
-    if (byte == eof) return 'EOF';
-    return '$byte (0x${byte.toRadixString(16).padLeft(2, "0")})';
+  ByteSink sink = new ByteSink();
+  new BinaryPrinter(sink).writeComponentFile(component);
+  List<int> writtenBytes = sink.builder.takeBytes();
+  if (bytes.length != writtenBytes.length) {
+    throw "Byte-lengths differ: ${bytes.length} vs ${writtenBytes.length}";
   }
-
-  @override
-  void writeByte(int byte) {
-    if (offset == expectedBytes.length || expectedBytes[offset] != byte) {
-      int expected =
-          (offset >= expectedBytes.length) ? eof : expectedBytes[offset];
-      throw 'At offset $offset: '
-          'Expected ${show(expected)} but found ${show(byte)}';
+  for (int i = 0; i < bytes.length; i++) {
+    if (bytes[i] != writtenBytes[i]) {
+      throw "Byte differs at index $i: "
+          "${show(bytes[i])} vs ${show(writtenBytes[i])}";
     }
-    ++offset;
+  }
+  print("OK");
+}
+
+String show(int byte) {
+  return '$byte (0x${byte.toRadixString(16).padLeft(2, "0")})';
+}
+
+/// A [Sink] that directly writes data into a byte builder.
+class ByteSink implements Sink<List<int>> {
+  final BytesBuilder builder = new BytesBuilder();
+
+  void add(List<int> data) {
+    builder.add(data);
   }
 
-  @override
-  void writeBytes(List<int> bytes) {
-    bytes.forEach(writeByte);
-  }
+  void close() {}
 }
diff --git a/pkg/nnbd_migration/lib/instrumentation.dart b/pkg/nnbd_migration/lib/instrumentation.dart
index 7b52b3c..558c1d4 100644
--- a/pkg/nnbd_migration/lib/instrumentation.dart
+++ b/pkg/nnbd_migration/lib/instrumentation.dart
@@ -94,6 +94,9 @@
 /// Information exposed to the migration client about the location in source
 /// code that led an edge to be introduced into the nullability graph.
 abstract class EdgeOriginInfo {
+  /// The kind of origin represented by this info.
+  EdgeOriginKind get kind;
+
   /// The AST node that led the edge to be introduced into the nullability
   /// graph.
   AstNode get node;
@@ -102,6 +105,29 @@
   Source get source;
 }
 
+/// An enumeration of the various kinds of edge origins created by the migration
+/// engine.
+enum EdgeOriginKind {
+  alwaysNullableType,
+  compoundAssignment,
+  defaultValue,
+  expressionChecks,
+  fieldFormalParameter,
+  forEachVariable,
+  greatestLowerBound,
+  ifNull,
+  implicitMixinSuperCall,
+  inheritance,
+  initializerInference,
+  instantiateToBounds,
+  isCheckComponentType,
+  isCheckMainType,
+  namedParameterNotSupplied,
+  nonNullAssertion,
+  nullabilityComment,
+  optionalFormalParameter,
+}
+
 /// Interface used by the migration engine to expose information to its client
 /// about a reason for a modification to the source file.
 abstract class FixReasonInfo {}
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index 2952664..f2b03b4 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -7,7 +7,6 @@
 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/element/handle.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';
@@ -27,6 +26,7 @@
 import 'package:nnbd_migration/src/nullability_node.dart';
 import 'package:nnbd_migration/src/utilities/annotation_tracker.dart';
 import 'package:nnbd_migration/src/utilities/permissive_mode.dart';
+import 'package:nnbd_migration/src/utilities/resolution_utils.dart';
 import 'package:nnbd_migration/src/utilities/scoped_set.dart';
 
 import 'decorated_type_operations.dart';
@@ -39,7 +39,7 @@
   final TypeSystem _typeSystem;
 
   @override
-  final TypeProvider _typeProvider;
+  final TypeProvider typeProvider;
 
   final NullabilityGraph _graph;
 
@@ -50,7 +50,7 @@
   @override
   final DecoratedClassHierarchy _decoratedClassHierarchy;
 
-  AssignmentCheckerForTesting(this._typeSystem, this._typeProvider, this._graph,
+  AssignmentCheckerForTesting(this._typeSystem, this.typeProvider, this._graph,
       this._decoratedClassHierarchy);
 
   void checkAssignment(EdgeOrigin origin,
@@ -86,7 +86,8 @@
     with
         _AssignmentChecker,
         PermissiveModeVisitor<DecoratedType>,
-        AnnotationTracker<DecoratedType> {
+        AnnotationTracker<DecoratedType>,
+        ResolutionUtils {
   final TypeSystem _typeSystem;
 
   final InheritanceManager3 _inheritanceManager;
@@ -101,7 +102,7 @@
 
   final NullabilityGraph _graph;
 
-  TypeProvider _typeProvider;
+  TypeProvider typeProvider;
 
   @override
   final Source source;
@@ -189,19 +190,17 @@
   /// nullable.
   final Map<Expression, NullabilityNode> _conditionalNodes = {};
 
-  List<String> _objectGetNames;
-
-  EdgeBuilder(this._typeProvider, this._typeSystem, this._variables,
-      this._graph, this.source, this.listener, this._decoratedClassHierarchy,
+  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),
+        _notNullType = DecoratedType(typeProvider.objectType, _graph.never),
         _nonNullableBoolType =
-            DecoratedType(_typeProvider.boolType, _graph.never),
+            DecoratedType(typeProvider.boolType, _graph.never),
         _nonNullableTypeType =
-            DecoratedType(_typeProvider.typeType, _graph.never),
-        _nullType = DecoratedType(_typeProvider.nullType, _graph.always),
-        _dynamicType = DecoratedType(_typeProvider.dynamicType, _graph.always);
+            DecoratedType(typeProvider.typeType, _graph.never),
+        _nullType = DecoratedType(typeProvider.nullType, _graph.always),
+        _dynamicType = DecoratedType(typeProvider.dynamicType, _graph.always);
 
   /// Gets the decorated type of [element] from [_variables], performing any
   /// necessary substitutions.
@@ -325,24 +324,20 @@
   @override
   DecoratedType visitBinaryExpression(BinaryExpression node) {
     var operatorType = node.operator.type;
+    var leftOperand = node.leftOperand;
+    var rightOperand = node.rightOperand;
     if (operatorType == TokenType.EQ_EQ || operatorType == TokenType.BANG_EQ) {
-      assert(node.leftOperand is! NullLiteral); // TODO(paulberry)
-      var leftType = node.leftOperand.accept(this);
-      node.rightOperand.accept(this);
-      if (node.rightOperand is NullLiteral) {
+      assert(leftOperand is! NullLiteral); // TODO(paulberry)
+      var leftType = leftOperand.accept(this);
+      _flowAnalysis.equalityOp_rightBegin(leftOperand);
+      rightOperand.accept(this);
+      bool notEqual = operatorType == TokenType.BANG_EQ;
+      _flowAnalysis.equalityOp_end(node, rightOperand, notEqual: notEqual);
+      if (rightOperand is NullLiteral) {
         // TODO(paulberry): only set falseChecksNonNull in unconditional
         // control flow
-        bool notEqual = operatorType == TokenType.BANG_EQ;
-        bool isPure = false;
-        var leftOperand = node.leftOperand;
-        if (leftOperand is SimpleIdentifier) {
-          // TODO(paulberry): figure out what the rules for isPure should be.
-          isPure = true;
-          var element = leftOperand.staticElement;
-          if (element is PromotableElement) {
-            _flowAnalysis.conditionEqNull(node, element, notEqual: notEqual);
-          }
-        }
+        // TODO(paulberry): figure out what the rules for isPure should be.
+        bool isPure = leftOperand is SimpleIdentifier;
         var conditionInfo = _ConditionInfo(node,
             isPure: isPure,
             postDominatingIntent:
@@ -355,21 +350,21 @@
     } else if (operatorType == TokenType.AMPERSAND_AMPERSAND ||
         operatorType == TokenType.BAR_BAR) {
       bool isAnd = operatorType == TokenType.AMPERSAND_AMPERSAND;
-      _checkExpressionNotNull(node.leftOperand);
+      _checkExpressionNotNull(leftOperand);
       _flowAnalysis.logicalBinaryOp_rightBegin(node.leftOperand, isAnd: isAnd);
       _postDominatedLocals.doScoped(
-          action: () => _checkExpressionNotNull(node.rightOperand));
-      _flowAnalysis.logicalBinaryOp_end(node, node.rightOperand, isAnd: isAnd);
+          action: () => _checkExpressionNotNull(rightOperand));
+      _flowAnalysis.logicalBinaryOp_end(node, rightOperand, isAnd: isAnd);
       return _nonNullableBoolType;
     } else if (operatorType == TokenType.QUESTION_QUESTION) {
       DecoratedType expressionType;
-      var leftType = node.leftOperand.accept(this);
+      var leftType = leftOperand.accept(this);
       _flowAnalysis.ifNullExpression_rightBegin();
       try {
         _guards.add(leftType.node);
         DecoratedType rightType;
         _postDominatedLocals.doScoped(action: () {
-          rightType = node.rightOperand.accept(this);
+          rightType = rightOperand.accept(this);
         });
         var ifNullNode = NullabilityNode.forIfNotNull();
         expressionType = DecoratedType(node.staticType, ifNullNode);
@@ -382,23 +377,23 @@
       _variables.recordDecoratedExpressionType(node, expressionType);
       return expressionType;
     } else if (operatorType.isUserDefinableOperator) {
-      var targetType = _checkExpressionNotNull(node.leftOperand);
+      var targetType = _checkExpressionNotNull(leftOperand);
       var callee = node.staticElement;
       if (callee == null) {
-        node.rightOperand.accept(this);
+        rightOperand.accept(this);
         return _dynamicType;
       } else {
         var calleeType =
             getOrComputeElementType(callee, targetType: targetType);
         assert(calleeType.positionalParameters.length > 0); // TODO(paulberry)
-        _handleAssignment(node.rightOperand,
+        _handleAssignment(rightOperand,
             destinationType: calleeType.positionalParameters[0]);
         return _fixNumericTypes(calleeType.returnType, node.staticType);
       }
     } else {
       // TODO(paulberry)
-      node.leftOperand.accept(this);
-      node.rightOperand.accept(this);
+      leftOperand.accept(this);
+      rightOperand.accept(this);
       _unimplemented(
           node, 'Binary expression with operator ${node.operator.lexeme}');
     }
@@ -438,7 +433,7 @@
       node.stackTraceParameter
     ]) {
       if (identifier != null) {
-        _flowAnalysis.write(identifier.staticElement as PromotableElement);
+        _flowAnalysis.initialize(identifier.staticElement as PromotableElement);
       }
     }
     // The catch clause may not execute, so create a new scope for
@@ -459,9 +454,6 @@
     var classElement = node.declaredElement;
     var supertype = classElement.supertype;
     var superElement = supertype.element;
-    if (superElement is ClassElementHandle) {
-      superElement = (superElement as ClassElementHandle).actualElement;
-    }
     for (var constructorElement in classElement.constructors) {
       assert(constructorElement.isSynthetic);
       var superConstructorElement =
@@ -571,7 +563,9 @@
   @override
   DecoratedType visitDoStatement(DoStatement node) {
     _flowAnalysis.doStatement_bodyBegin(
-        node, _assignedVariables.writtenInNode(node));
+        node,
+        _assignedVariables.writtenInNode(node),
+        _assignedVariables.capturedInNode(node));
     node.body.accept(this);
     _flowAnalysis.doStatement_conditionBegin();
     _checkExpressionNotNull(node.condition);
@@ -593,21 +587,8 @@
           '(parent is ${node.parent.runtimeType})');
     }
     _handleAssignment(node.expression,
-        destinationType: _currentFunctionType.returnType);
-    return null;
-  }
-
-  @override
-  DecoratedType visitFieldDeclaration(FieldDeclaration node) {
-    node.metadata.accept(this);
-    _createFlowAnalysis(node);
-    try {
-      node.fields.accept(this);
-    } finally {
-      _flowAnalysis.finish();
-      _flowAnalysis = null;
-      _assignedVariables = null;
-    }
+        destinationType: _currentFunctionType.returnType,
+        wrapFuture: node.isAsynchronous);
     return null;
   }
 
@@ -646,7 +627,7 @@
       // This is a local function.
       node.functionExpression.accept(this);
     } else {
-      _createFlowAnalysis(node.functionExpression.body);
+      _createFlowAnalysis(node, node.functionExpression.parameters);
       // Initialize a new postDominator scope that contains only the parameters.
       try {
         node.functionExpression.accept(this);
@@ -809,7 +790,7 @@
       if (staticType is InterfaceType) {
         typeArgumentTypes = staticType.typeArguments;
         decoratedTypeArguments = typeArgumentTypes
-            .map((t) => DecoratedType.forImplicitType(_typeProvider, t, _graph))
+            .map((t) => DecoratedType.forImplicitType(typeProvider, t, _graph))
             .toList();
         instrumentation?.implicitTypeArguments(
             source, node, decoratedTypeArguments);
@@ -889,7 +870,7 @@
       var listType = node.staticType as InterfaceType;
       if (node.typeArguments == null) {
         var elementType = DecoratedType.forImplicitType(
-            _typeProvider, listType.typeArguments[0], _graph);
+            typeProvider, listType.typeArguments[0], _graph);
         instrumentation?.implicitTypeArguments(source, node, [elementType]);
         _currentLiteralElementType = elementType;
       } else {
@@ -924,7 +905,8 @@
   DecoratedType visitMethodInvocation(MethodInvocation node) {
     DecoratedType targetType;
     var target = node.realTarget;
-    bool isConditional = _isConditionalExpression(node);
+    var operator = node.operator;
+    bool isNullAware = operator != null && isNullAwareToken(operator.type);
     var callee = node.methodName.staticElement;
     bool calleeIsStatic = callee is ExecutableElement && callee.isStatic;
     if (target != null) {
@@ -932,7 +914,7 @@
         // Nothing to do.
       } else if (calleeIsStatic) {
         target.accept(this);
-      } else if (isConditional) {
+      } else if (isNullAware) {
         targetType = target.accept(this);
       } else {
         targetType = _handleTarget(target, node.methodName.name);
@@ -962,7 +944,7 @@
         calleeType,
         null,
         invokeType: node.staticInvokeType);
-    if (isConditional) {
+    if (isNullAware) {
       expressionType = expressionType.withNode(
           NullabilityNode.forLUB(targetType.node, expressionType.node));
       _variables.recordDecoratedExpressionType(node, expressionType);
@@ -979,12 +961,15 @@
 
   @override
   DecoratedType visitNullLiteral(NullLiteral node) {
+    _flowAnalysis.nullLiteral(node);
     return _nullType;
   }
 
   @override
   DecoratedType visitParenthesizedExpression(ParenthesizedExpression node) {
-    return node.expression.accept(this);
+    var result = node.expression.accept(this);
+    _flowAnalysis.parenthesizedExpression(node, node.expression);
+    return result;
   }
 
   @override
@@ -999,21 +984,7 @@
     var operatorType = node.operator.type;
     if (operatorType == TokenType.PLUS_PLUS ||
         operatorType == TokenType.MINUS_MINUS) {
-      _checkExpressionNotNull(node.operand);
-      var callee = node.staticElement;
-      if (callee is ClassMemberElement &&
-          (callee.enclosingElement as ClassElement).typeParameters.isNotEmpty) {
-        // TODO(paulberry)
-        _unimplemented(node,
-            'Operator ${operatorType.lexeme} defined on a class with type parameters');
-      }
-      if (callee == null) {
-        // TODO(paulberry)
-        _unimplemented(node, 'Unresolved operator ${operatorType.lexeme}');
-      }
-      var calleeType = getOrComputeElementType(callee);
-      // TODO(paulberry): substitute if necessary
-      return _fixNumericTypes(calleeType.returnType, node.staticType);
+      return _checkExpressionNotNull(node.operand);
     }
     _unimplemented(
         node, 'Postfix expression with operator ${node.operator.lexeme}');
@@ -1025,7 +996,7 @@
       // TODO(paulberry)
       _unimplemented(node, 'PrefixedIdentifier with a prefix');
     } else {
-      return _handlePropertyAccess(node, node.prefix, node.identifier);
+      return _handlePropertyAccess(node, node.prefix, node.identifier, false);
     }
   }
 
@@ -1036,32 +1007,29 @@
     if (operatorType == TokenType.BANG) {
       _flowAnalysis.logicalNot_end(node, node.operand);
       return _nonNullableBoolType;
-    } else if (operatorType == TokenType.PLUS_PLUS ||
-        operatorType == TokenType.MINUS_MINUS) {
-      var callee = node.staticElement;
-      if (callee is ClassMemberElement &&
-          (callee.enclosingElement as ClassElement).typeParameters.isNotEmpty) {
-        // TODO(paulberry)
-        _unimplemented(node,
-            'Operator ${operatorType.lexeme} defined on a class with type parameters');
-      }
-      if (callee == null) {
-        // TODO(paulberry)
-        _unimplemented(node, 'Unresolved operator ${operatorType.lexeme}');
-      }
-      var calleeType = getOrComputeElementType(callee);
-      // TODO(paulberry): substitute if necessary
-      return _fixNumericTypes(calleeType.returnType, node.staticType);
     } else {
       var callee = node.staticElement;
+      if (callee == null) {
+        // 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;
+      }
       var calleeType = getOrComputeElementType(callee, targetType: targetType);
-      return _handleInvocationArguments(node, [], null, null, calleeType, null);
+      if (operatorType == TokenType.PLUS_PLUS ||
+          operatorType == TokenType.MINUS_MINUS) {
+        return _fixNumericTypes(calleeType.returnType, node.staticType);
+      } else {
+        return _handleInvocationArguments(
+            node, [], null, null, calleeType, null);
+      }
     }
   }
 
   @override
   DecoratedType visitPropertyAccess(PropertyAccess node) {
-    return _handlePropertyAccess(node, node.realTarget, node.propertyName);
+    return _handlePropertyAccess(node, node.realTarget, node.propertyName,
+        isNullAwareToken(node.operator.type));
   }
 
   @override
@@ -1084,19 +1052,15 @@
   DecoratedType visitReturnStatement(ReturnStatement node) {
     DecoratedType returnType = _currentFunctionType.returnType;
     Expression returnValue = node.expression;
-    // TODO(danrubel): This does not handle situations where the returnType
-    // or the returnValue's type extends or implements dart:async Future.
-    if ((returnType.type.isDartAsyncFuture ||
-            returnType.type.isDartAsyncFutureOr) &&
-        node.thisOrAncestorOfType<FunctionBody>().isAsynchronous &&
-        !returnValue.staticType.isDartAsyncFuture) {
-      returnType = returnType.typeArguments.first;
-    }
+    final isAsync = node.thisOrAncestorOfType<FunctionBody>().isAsynchronous;
     if (returnValue == null) {
       _checkAssignment(null,
-          source: _nullType, destination: returnType, hard: false);
+          source: isAsync ? _futureOf(_nullType) : _nullType,
+          destination: returnType,
+          hard: false);
     } else {
-      _handleAssignment(returnValue, destinationType: returnType);
+      _handleAssignment(returnValue,
+          destinationType: returnType, wrapFuture: isAsync);
     }
 
     _flowAnalysis.handleExit();
@@ -1119,7 +1083,7 @@
         if (typeArguments == null) {
           assert(setOrMapType.typeArguments.length == 1);
           var elementType = DecoratedType.forImplicitType(
-              _typeProvider, setOrMapType.typeArguments[0], _graph);
+              typeProvider, setOrMapType.typeArguments[0], _graph);
           instrumentation?.implicitTypeArguments(source, node, [elementType]);
           _currentLiteralElementType = elementType;
         } else {
@@ -1142,10 +1106,10 @@
         if (typeArguments == null) {
           assert(setOrMapType.typeArguments.length == 2);
           var keyType = DecoratedType.forImplicitType(
-              _typeProvider, setOrMapType.typeArguments[0], _graph);
+              typeProvider, setOrMapType.typeArguments[0], _graph);
           _currentMapKeyType = keyType;
           var valueType = DecoratedType.forImplicitType(
-              _typeProvider, setOrMapType.typeArguments[1], _graph);
+              typeProvider, setOrMapType.typeArguments[1], _graph);
           _currentMapValueType = valueType;
           instrumentation
               ?.implicitTypeArguments(source, node, [keyType, valueType]);
@@ -1172,7 +1136,7 @@
     var staticElement = node.staticElement;
     if (staticElement is PromotableElement) {
       if (!node.inDeclarationContext()) {
-        var promotedType = _flowAnalysis.promotedType(staticElement);
+        var promotedType = _flowAnalysis.variableRead(node, staticElement);
         if (promotedType != null) return promotedType;
       }
       return getOrComputeElementType(staticElement);
@@ -1196,24 +1160,23 @@
   @override
   DecoratedType visitSpreadElement(SpreadElement node) {
     final spreadType = node.expression.staticType;
-    if (_typeSystem.isSubtypeOf(
-        spreadType, _typeProvider.mapObjectObjectType)) {
+    if (_typeSystem.isSubtypeOf(spreadType, typeProvider.mapObjectObjectType)) {
       assert(_currentMapKeyType != null && _currentMapValueType != null);
-      final expectedType = _typeProvider.mapType2(
+      final expectedType = typeProvider.mapType2(
           _currentMapKeyType.type, _currentMapValueType.type);
       final expectedDecoratedType = DecoratedType.forImplicitType(
-          _typeProvider, expectedType, _graph,
+          typeProvider, expectedType, _graph,
           typeArguments: [_currentMapKeyType, _currentMapValueType]);
 
       _handleAssignment(node.expression,
           destinationType: expectedDecoratedType);
     } else if (_typeSystem.isSubtypeOf(
-        spreadType, _typeProvider.iterableDynamicType)) {
+        spreadType, typeProvider.iterableDynamicType)) {
       assert(_currentLiteralElementType != null);
       final expectedType =
-          _typeProvider.iterableType2(_currentLiteralElementType.type);
+          typeProvider.iterableType2(_currentLiteralElementType.type);
       final expectedDecoratedType = DecoratedType.forImplicitType(
-          _typeProvider, expectedType, _graph,
+          typeProvider, expectedType, _graph,
           typeArguments: [_currentLiteralElementType]);
 
       _handleAssignment(node.expression,
@@ -1245,10 +1208,11 @@
     node.expression.accept(this);
     _flowAnalysis.switchStatement_expressionEnd(node);
     var notPromoted = _assignedVariables.writtenInNode(node);
+    var captured = _assignedVariables.capturedInNode(node);
     var hasDefault = false;
     for (var member in node.members) {
       var hasLabel = member.labels.isNotEmpty;
-      _flowAnalysis.switchStatement_beginCase(hasLabel, notPromoted);
+      _flowAnalysis.switchStatement_beginCase(hasLabel, notPromoted, captured);
       if (member is SwitchCase) {
         member.expression.accept(this);
       } else {
@@ -1279,21 +1243,6 @@
   }
 
   @override
-  DecoratedType visitTopLevelVariableDeclaration(
-      TopLevelVariableDeclaration node) {
-    node.metadata.accept(this);
-    _createFlowAnalysis(node);
-    try {
-      node.variables.accept(this);
-    } finally {
-      _flowAnalysis.finish();
-      _flowAnalysis = null;
-      _assignedVariables = null;
-    }
-    return null;
-  }
-
-  @override
   DecoratedType visitTryStatement(TryStatement node) {
     var finallyBlock = node.finallyBlock;
     if (finallyBlock != null) {
@@ -1306,13 +1255,15 @@
     var body = node.body;
     body.accept(this);
     var assignedInBody = _assignedVariables.writtenInNode(body);
+    var capturedInBody = _assignedVariables.capturedInNode(body);
     if (catchClauses.isNotEmpty) {
-      _flowAnalysis.tryCatchStatement_bodyEnd(assignedInBody);
+      _flowAnalysis.tryCatchStatement_bodyEnd(assignedInBody, capturedInBody);
       catchClauses.accept(this);
       _flowAnalysis.tryCatchStatement_end();
     }
     if (finallyBlock != null) {
-      _flowAnalysis.tryFinallyStatement_finallyBegin(assignedInBody);
+      _flowAnalysis.tryFinallyStatement_finallyBegin(
+          assignedInBody, capturedInBody);
       finallyBlock.accept(this);
       _flowAnalysis.tryFinallyStatement_end(
           _assignedVariables.writtenInNode(finallyBlock));
@@ -1361,27 +1312,45 @@
 
   @override
   DecoratedType visitVariableDeclarationList(VariableDeclarationList node) {
+    var parent = node.parent;
+    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;
       var declaredElement = variable.declaredElement;
-      if (declaredElement is PromotableElement && initializer != null) {
-        _flowAnalysis.write(declaredElement);
+      if (isTopLevel) {
+        assert(_flowAnalysis == null);
+        _createFlowAnalysis(variable, null);
+      } else {
+        assert(_flowAnalysis != null);
       }
-      if (initializer != null) {
-        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}');
+      try {
+        if (initializer != null) {
+          if (declaredElement is PromotableElement) {
+            _flowAnalysis.initialize(declaredElement);
           }
-          _unionDecoratedTypes(initializerType, destinationType,
-              InitializerInferenceOrigin(source, variable));
-        } else {
-          _handleAssignment(initializer, destinationType: destinationType);
+          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);
+          }
+        }
+      } finally {
+        if (isTopLevel) {
+          _flowAnalysis.finish();
+          _flowAnalysis = null;
+          _assignedVariables = null;
         }
       }
     }
@@ -1404,8 +1373,9 @@
   DecoratedType visitWhileStatement(WhileStatement node) {
     // Note: we do not create guards. A null check here is *very* unlikely to be
     // unnecessary after analysis.
-    _flowAnalysis
-        .whileStatement_conditionBegin(_assignedVariables.writtenInNode(node));
+    _flowAnalysis.whileStatement_conditionBegin(
+        _assignedVariables.writtenInNode(node),
+        _assignedVariables.capturedInNode(node));
     _checkExpressionNotNull(node.condition);
     _flowAnalysis.whileStatement_bodyBegin(node, node.condition);
     _postDominatedLocals.doScoped(action: () => node.body.accept(this));
@@ -1416,7 +1386,7 @@
   void _addParametersToFlowAnalysis(FormalParameterList parameters) {
     if (parameters != null) {
       for (var parameter in parameters.parameters) {
-        _flowAnalysis.write(parameter.declaredElement);
+        _flowAnalysis.initialize(parameter.declaredElement);
       }
     }
   }
@@ -1436,21 +1406,6 @@
     return _handleAssignment(expression, destinationType: _notNullType);
   }
 
-  List<String> _computeObjectGetNames() {
-    var result = <String>[];
-    var objectClass = _typeProvider.objectType.element;
-    for (var accessor in objectClass.accessors) {
-      assert(accessor.isGetter);
-      assert(!accessor.name.startsWith('_'));
-      result.add(accessor.name);
-    }
-    for (var method in objectClass.methods) {
-      assert(!method.name.startsWith('_'));
-      result.add(method.name);
-    }
-    return result;
-  }
-
   @override
   void _connect(
       NullabilityNode source, NullabilityNode destination, EdgeOrigin origin,
@@ -1462,15 +1417,16 @@
     }
   }
 
-  void _createFlowAnalysis(AstNode node) {
+  void _createFlowAnalysis(Declaration node, FormalParameterList parameters) {
     assert(_flowAnalysis == null);
     assert(_assignedVariables == null);
+    _assignedVariables =
+        FlowAnalysisHelper.computeAssignedVariables(node, parameters);
     _flowAnalysis =
         FlowAnalysis<Statement, Expression, PromotableElement, DecoratedType>(
-            const AnalyzerNodeOperations(),
             DecoratedTypeOperations(_typeSystem, _variables, _graph),
-            AnalyzerFunctionBodyAccess(node is FunctionBody ? node : null));
-    _assignedVariables = FlowAnalysisHelper.computeAssignedVariables(node);
+            _assignedVariables.writtenAnywhere,
+            _assignedVariables.capturedAnywhere);
   }
 
   DecoratedType _decorateUpperOrLowerBound(AstNode astNode, DartType type,
@@ -1571,6 +1527,10 @@
     }
   }
 
+  DecoratedType _futureOf(DecoratedType type) => DecoratedType.forImplicitType(
+      typeProvider, typeProvider.futureType2(type.type), _graph,
+      typeArguments: [type]);
+
   @override
   DecoratedType _getTypeParameterTypeBound(DecoratedType type) {
     // TODO(paulberry): once we've wired up flow analysis, return promoted
@@ -1586,12 +1546,15 @@
   /// [destinationType].  In this case, then the type comes from visiting the
   /// destination expression.  If the destination expression refers to a local
   /// variable, we mark it as assigned in flow analysis at the proper time.
+  ///
+  /// Set [wrapFuture] to true to handle assigning Future<flatten(T)> to R.
   DecoratedType _handleAssignment(Expression expression,
       {DecoratedType destinationType,
       Expression destinationExpression,
       AssignmentExpression compoundOperatorInfo,
       Expression questionAssignNode,
-      bool fromDefaultValue = false}) {
+      bool fromDefaultValue = false,
+      bool wrapFuture = false}) {
     assert(
         (destinationExpression == null) != (destinationType == null),
         'Either destinationExpression or destinationType should be supplied, '
@@ -1617,6 +1580,9 @@
     DecoratedType sourceType;
     try {
       sourceType = expression.accept(this);
+      if (wrapFuture) {
+        sourceType = _wrapFuture(sourceType);
+      }
       if (sourceType == null) {
         throw StateError('No type computed for ${expression.runtimeType} '
             '(${expression.toSource()}) offset=${expression.offset}');
@@ -1720,7 +1686,7 @@
   }
 
   void _handleExecutableDeclaration(
-      AstNode node,
+      Declaration node,
       ExecutableElement declaredElement,
       NodeList<Annotation> metadata,
       TypeAnnotation returnType,
@@ -1731,7 +1697,7 @@
     assert(_currentFunctionType == null);
     metadata.accept(this);
     returnType?.accept(this);
-    _createFlowAnalysis(body);
+    _createFlowAnalysis(node, parameters);
     parameters?.accept(this);
     _currentFunctionType = _variables.decoratedElementType(declaredElement);
     _addParametersToFlowAnalysis(parameters);
@@ -1835,7 +1801,8 @@
       } else if (parts is ForPartsWithExpression) {
         parts.initialization?.accept(this);
       }
-      _flowAnalysis.for_conditionBegin(_assignedVariables.writtenInNode(node));
+      _flowAnalysis.for_conditionBegin(_assignedVariables.writtenInNode(node),
+          _assignedVariables.capturedInNode(node));
       if (parts.condition != null) {
         _checkExpressionNotNull(parts.condition);
       }
@@ -1857,16 +1824,18 @@
         DecoratedType lhsType = _variables.decoratedElementType(lhsElement);
         var iterableTypeType = iterableType.type;
         if (_typeSystem.isSubtypeOf(
-            iterableTypeType, _typeProvider.iterableDynamicType)) {
+            iterableTypeType, typeProvider.iterableDynamicType)) {
           var elementType = _decoratedClassHierarchy
               .asInstanceOf(
-                  iterableType, _typeProvider.iterableDynamicType.element)
+                  iterableType, typeProvider.iterableDynamicType.element)
               .typeArguments[0];
           _checkAssignment(ForEachVariableOrigin(source, parts),
               source: elementType, destination: lhsType, hard: false);
         }
       }
-      _flowAnalysis.forEach_bodyBegin(_assignedVariables.writtenInNode(node),
+      _flowAnalysis.forEach_bodyBegin(
+          _assignedVariables.writtenInNode(node),
+          _assignedVariables.capturedInNode(node),
           lhsElement is PromotableElement ? lhsElement : null);
     }
 
@@ -1933,7 +1902,7 @@
         if (invokeType is FunctionType) {
           var argumentTypes = typeArgumentTypes
               .map((argType) =>
-                  DecoratedType.forImplicitType(_typeProvider, argType, _graph))
+                  DecoratedType.forImplicitType(typeProvider, argType, _graph))
               .toList();
           instrumentation?.implicitTypeArguments(source, node, argumentTypes);
           calleeType = calleeType.instantiate(argumentTypes);
@@ -1990,17 +1959,16 @@
     return calleeType.returnType;
   }
 
-  DecoratedType _handlePropertyAccess(
-      Expression node, Expression target, SimpleIdentifier propertyName) {
+  DecoratedType _handlePropertyAccess(Expression node, Expression target,
+      SimpleIdentifier propertyName, bool isNullAware) {
     DecoratedType targetType;
-    bool isConditional = _isConditionalExpression(node);
     var callee = propertyName.staticElement;
     bool calleeIsStatic = callee is ExecutableElement && callee.isStatic;
     if (_isPrefix(target)) {
       return propertyName.accept(this);
     } else if (calleeIsStatic) {
       target.accept(this);
-    } else if (isConditional) {
+    } else if (isNullAware) {
       targetType = target.accept(this);
     } else {
       targetType = _handleTarget(target, propertyName.name);
@@ -2012,7 +1980,7 @@
     var calleeType = getOrComputeElementType(callee, targetType: targetType);
     // TODO(paulberry): substitute if necessary
     if (propertyName.inSetterContext()) {
-      if (isConditional) {
+      if (isNullAware) {
         _conditionalNodes[node] = targetType.node;
       }
       return calleeType.positionalParameters[0];
@@ -2020,7 +1988,7 @@
       var expressionType = callee is PropertyAccessorElement
           ? calleeType.returnType
           : calleeType;
-      if (isConditional) {
+      if (isNullAware) {
         expressionType = expressionType.withNode(
             NullabilityNode.forLUB(targetType.node, expressionType.node));
         _variables.recordDecoratedExpressionType(node, expressionType);
@@ -2030,7 +1998,7 @@
   }
 
   DecoratedType _handleTarget(Expression target, String name) {
-    if ((_objectGetNames ??= _computeObjectGetNames()).contains(name)) {
+    if (isDeclaredOnObject(name)) {
       return target.accept(this);
     } else {
       return _checkExpressionNotNull(target);
@@ -2050,29 +2018,6 @@
             .toList());
   }
 
-  bool _isConditionalExpression(Expression expression) {
-    Token token;
-    if (expression is MethodInvocation) {
-      token = expression.operator;
-      if (token == null) return false;
-    } else if (expression is PropertyAccess) {
-      token = expression.operator;
-    } else {
-      return false;
-    }
-    switch (token.type) {
-      case TokenType.PERIOD:
-      case TokenType.PERIOD_PERIOD:
-        return false;
-      case TokenType.QUESTION_PERIOD:
-        return true;
-      default:
-        // TODO(paulberry)
-        _unimplemented(
-            expression, 'Conditional expression with operator ${token.lexeme}');
-    }
-  }
-
   bool _isPrefix(Expression e) =>
       e is SimpleIdentifier && e.staticElement is PrefixElement;
 
@@ -2140,6 +2085,18 @@
       _unionDecoratedTypes(x.returnType, y.returnType, origin);
     }
   }
+
+  /// Produce Future<flatten(T)> for some T, however, we would like to merely
+  /// upcast T to that type if possible, skipping the flatten when not
+  /// necessary.
+  DecoratedType _wrapFuture(DecoratedType type) {
+    if (_typeSystem.isSubtypeOf(type.type, typeProvider.futureDynamicType)) {
+      return _decoratedClassHierarchy.asInstanceOf(
+          type, typeProvider.futureDynamicType.element);
+    }
+
+    return _futureOf(type);
+  }
 }
 
 /// Implementation of [_checkAssignment] for [EdgeBuilder].
@@ -2147,12 +2104,12 @@
 /// This has been moved to its own mixin to allow it to be more easily unit
 /// tested.
 mixin _AssignmentChecker {
+  TypeProvider get typeProvider;
+
   DecoratedClassHierarchy get _decoratedClassHierarchy;
 
   NullabilityGraph get _graph;
 
-  TypeProvider get _typeProvider;
-
   TypeSystem get _typeSystem;
 
   /// Creates the necessary constraint(s) for an assignment from [source] to
@@ -2234,7 +2191,7 @@
       // if T1 is FutureOr<S1> then T0 <: T1 iff any of the following hold:
       // - either T0 <: Future<S1>
       if (_typeSystem.isSubtypeOf(
-          sourceType, _typeProvider.futureType2(s1.type))) {
+          sourceType, typeProvider.futureType2(s1.type))) {
         // E.g. FutureOr<int> = (... as Future<int>)
         // This is handled by the InterfaceType logic below, since we treat
         // FutureOr as a supertype of Future.
@@ -2338,7 +2295,7 @@
       if (destination.type is ParameterizedType) {
         for (final param
             in (destination.type as ParameterizedType).typeParameters) {
-          assert(param.type.bound.isDynamic,
+          assert(param.bound == null,
               'downcast to type parameters with bounds not supported');
         }
       }
@@ -2361,14 +2318,14 @@
       if (destination.type is ParameterizedType) {
         for (final param
             in (destination.type as ParameterizedType).typeParameters) {
-          assert(param.type.bound.isDynamic,
+          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),
+            source: DecoratedType(typeProvider.dynamicType, _graph.always),
             destination: arg,
             hard: false);
       }
diff --git a/pkg/nnbd_migration/lib/src/edge_origin.dart b/pkg/nnbd_migration/lib/src/edge_origin.dart
index 94133d5..ec94adce 100644
--- a/pkg/nnbd_migration/lib/src/edge_origin.dart
+++ b/pkg/nnbd_migration/lib/src/edge_origin.dart
@@ -16,6 +16,9 @@
 /// nullable.
 class AlwaysNullableTypeOrigin extends EdgeOrigin {
   AlwaysNullableTypeOrigin(Source source, AstNode node) : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.alwaysNullableType;
 }
 
 /// Edge origin resulting from the use of a value on the LHS of a compound
@@ -25,6 +28,9 @@
       : super(source, node);
 
   @override
+  EdgeOriginKind get kind => EdgeOriginKind.compoundAssignment;
+
+  @override
   AssignmentExpression get node => super.node as AssignmentExpression;
 }
 
@@ -32,6 +38,9 @@
 /// a parameter.
 class DefaultValueOrigin extends EdgeOrigin {
   DefaultValueOrigin(Source source, Expression node) : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.defaultValue;
 }
 
 /// Common interface for classes providing information about how an edge came
@@ -52,6 +61,9 @@
 class FieldFormalParameterOrigin extends EdgeOrigin {
   FieldFormalParameterOrigin(Source source, FieldFormalParameter node)
       : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.fieldFormalParameter;
 }
 
 /// Edge origin resulting from the use of an iterable type in a for-each loop.
@@ -65,6 +77,9 @@
 /// parameter to the type of `i`.
 class ForEachVariableOrigin extends EdgeOrigin {
   ForEachVariableOrigin(Source source, ForEachParts node) : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.forEachVariable;
 }
 
 /// Edge origin resulting from the use of greatest lower bound.
@@ -78,11 +93,17 @@
 /// is the greatest lower bound of the two other `int`s.
 class GreatestLowerBoundOrigin extends EdgeOrigin {
   GreatestLowerBoundOrigin(Source source, AstNode node) : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.greatestLowerBound;
 }
 
 /// Edge origin resulting from the presence of a `??` operator.
 class IfNullOrigin extends EdgeOrigin {
   IfNullOrigin(Source source, AstNode node) : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.ifNull;
 }
 
 /// Edge origin resulting from the implicit call from a mixin application
@@ -101,17 +122,26 @@
 class ImplicitMixinSuperCallOrigin extends EdgeOrigin {
   ImplicitMixinSuperCallOrigin(Source source, ClassTypeAlias node)
       : super(source, node);
+
+  @override
+  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)
       : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.initializerInference;
 }
 
 /// Edge origin resulting from a class that is instantiated to bounds.
@@ -124,6 +154,9 @@
 /// with the type bound in the declaration of C.
 class InstantiateToBoundsOrigin extends EdgeOrigin {
   InstantiateToBoundsOrigin(Source source, TypeName node) : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.instantiateToBounds;
 }
 
 /// Edge origin resulting from the use of a type as a component type in an 'is'
@@ -135,6 +168,9 @@
 class IsCheckComponentTypeOrigin extends EdgeOrigin {
   IsCheckComponentTypeOrigin(Source source, TypeAnnotation node)
       : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.isCheckComponentType;
 }
 
 /// Edge origin resulting from the use of a type as the main type in an 'is'
@@ -145,6 +181,9 @@
 class IsCheckMainTypeOrigin extends EdgeOrigin {
   IsCheckMainTypeOrigin(Source source, TypeAnnotation node)
       : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.isCheckMainType;
 }
 
 /// Edge origin resulting from a call site that does not supply a named
@@ -162,6 +201,9 @@
 class NamedParameterNotSuppliedOrigin extends EdgeOrigin {
   NamedParameterNotSuppliedOrigin(Source source, AstNode node)
       : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.namedParameterNotSupplied;
 }
 
 /// Edge origin resulting from the presence of a non-null assertion.
@@ -175,6 +217,9 @@
 /// `never`, due to the assert statement proclaiming that `i` is not `null`.
 class NonNullAssertionOrigin extends EdgeOrigin {
   NonNullAssertionOrigin(Source source, Assertion node) : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.nonNullAssertion;
 }
 
 /// Edge origin resulting from the presence of an explicit nullability hint
@@ -188,6 +233,9 @@
 class NullabilityCommentOrigin extends EdgeOrigin {
   NullabilityCommentOrigin(Source source, TypeAnnotation node)
       : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.nullabilityComment;
 }
 
 /// Edge origin resulting from the presence of an optional formal parameter.
@@ -200,4 +248,7 @@
 class OptionalFormalParameterOrigin extends EdgeOrigin {
   OptionalFormalParameterOrigin(Source source, DefaultFormalParameter node)
       : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.optionalFormalParameter;
 }
diff --git a/pkg/nnbd_migration/lib/src/expression_checks.dart b/pkg/nnbd_migration/lib/src/expression_checks.dart
index 1dffb8d..dd7ba9f 100644
--- a/pkg/nnbd_migration/lib/src/expression_checks.dart
+++ b/pkg/nnbd_migration/lib/src/expression_checks.dart
@@ -84,4 +84,7 @@
 
   ExpressionChecksOrigin(Source source, Expression node, this.checks)
       : super(source, node);
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.expressionChecks;
 }
diff --git a/pkg/nnbd_migration/lib/src/fix_builder.dart b/pkg/nnbd_migration/lib/src/fix_builder.dart
index af058ad..c686258 100644
--- a/pkg/nnbd_migration/lib/src/fix_builder.dart
+++ b/pkg/nnbd_migration/lib/src/fix_builder.dart
@@ -14,9 +14,11 @@
 import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
 import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/source.dart';
 import 'package:front_end/src/fasta/flow_analysis/flow_analysis.dart';
 import 'package:meta/meta.dart';
 import 'package:nnbd_migration/src/decorated_class_hierarchy.dart';
+import 'package:nnbd_migration/src/utilities/resolution_utils.dart';
 import 'package:nnbd_migration/src/variables.dart';
 
 /// Information about the target of an assignment expression analyzed by
@@ -65,12 +67,13 @@
 /// to figure out what changes need to be made to the code.  It doesn't actually
 /// make the changes; it simply reports what changes are necessary through
 /// abstract methods.
-abstract class FixBuilder extends GeneralizingAstVisitor<DartType> {
+abstract class FixBuilder extends GeneralizingAstVisitor<DartType>
+    with ResolutionUtils {
   /// The decorated class hierarchy for this migration run.
   final DecoratedClassHierarchy _decoratedClassHierarchy;
 
   /// Type provider providing non-nullable types.
-  final TypeProvider _typeProvider;
+  final TypeProvider typeProvider;
 
   /// The type system.
   final TypeSystem _typeSystem;
@@ -85,17 +88,24 @@
 
   /// If we are visiting a function body or initializer, assigned variable
   /// information  used in flow analysis.  Otherwise `null`.
-  AssignedVariables<AstNode, VariableElement> _assignedVariables;
+  AssignedVariables<AstNode, PromotableElement> _assignedVariables;
 
   /// If we are visiting a subexpression, the context type used for type
   /// inference.  This is used to determine when `!` needs to be inserted.
   DartType _contextType;
 
-  FixBuilder(this._decoratedClassHierarchy, TypeProvider typeProvider,
-      this._typeSystem, this._variables)
-      : _typeProvider = (typeProvider as TypeProviderImpl)
+  /// The file being analyzed.
+  final Source source;
+
+  FixBuilder(this.source, this._decoratedClassHierarchy,
+      TypeProvider typeProvider, this._typeSystem, this._variables)
+      : typeProvider = (typeProvider as TypeProviderImpl)
             .withNullability(NullabilitySuffix.none);
 
+  /// Called whenever a type annotation is found for which a `?` needs to be
+  /// inserted.
+  void addNullable(TypeAnnotation node);
+
   /// Called whenever an expression is found for which a `!` needs to be
   /// inserted.
   void addNullCheck(Expression subexpression);
@@ -104,23 +114,26 @@
   void addProblem(AstNode node, Problem problem);
 
   /// Initializes flow analysis for a function node.
-  void createFlowAnalysis(AstNode node) {
+  void createFlowAnalysis(Declaration node, FormalParameterList parameters) {
     assert(_flowAnalysis == null);
     assert(_assignedVariables == null);
+    _assignedVariables =
+        FlowAnalysisHelper.computeAssignedVariables(node, parameters);
     _flowAnalysis =
         FlowAnalysis<Statement, Expression, PromotableElement, DartType>(
-            const AnalyzerNodeOperations(),
             TypeSystemTypeOperations(_typeSystem),
-            AnalyzerFunctionBodyAccess(node is FunctionBody ? node : null));
-    _assignedVariables = FlowAnalysisHelper.computeAssignedVariables(node);
+            _assignedVariables.writtenAnywhere,
+            _assignedVariables.capturedAnywhere);
   }
 
   @override
   DartType visitAssignmentExpression(AssignmentExpression node) {
-    var targetInfo = visitAssignmentTarget(node.leftHandSide);
-    if (node.operator.type == TokenType.EQ) {
+    var operatorType = node.operator.type;
+    var targetInfo =
+        visitAssignmentTarget(node.leftHandSide, operatorType != TokenType.EQ);
+    if (operatorType == TokenType.EQ) {
       return visitSubexpression(node.rightHandSide, targetInfo.writeType);
-    } else if (node.operator.type == TokenType.QUESTION_QUESTION_EQ) {
+    } else if (operatorType == TokenType.QUESTION_QUESTION_EQ) {
       // TODO(paulberry): if targetInfo.readType is non-nullable, then the
       // assignment is dead code.
       // See https://github.com/dart-lang/sdk/issues/38678
@@ -135,8 +148,8 @@
       var combiner = node.staticElement;
       DartType combinedType;
       if (combiner == null) {
-        visitSubexpression(node.rightHandSide, _typeProvider.dynamicType);
-        combinedType = _typeProvider.dynamicType;
+        visitSubexpression(node.rightHandSide, typeProvider.dynamicType);
+        combinedType = typeProvider.dynamicType;
       } else {
         if (_typeSystem.isNullable(targetInfo.readType)) {
           addProblem(node, const CompoundAssignmentReadNullable());
@@ -157,14 +170,56 @@
 
   /// Recursively visits an assignment target, returning information about the
   /// target's read and write types.
-  AssignmentTargetInfo visitAssignmentTarget(Expression node) {
+  ///
+  /// If [isCompound] is true, the target is being both read from and written
+  /// to.  If it is false, then only the write type is needed.
+  AssignmentTargetInfo visitAssignmentTarget(Expression node, bool isCompound) {
     if (node is SimpleIdentifier) {
       var writeType = _computeMigratedType(node.staticElement);
       var auxiliaryElements = node.auxiliaryElements;
       var readType = auxiliaryElements == null
           ? writeType
           : _computeMigratedType(auxiliaryElements.staticElement);
+      return AssignmentTargetInfo(isCompound ? readType : null, writeType);
+    } else if (node is IndexExpression) {
+      var targetType = visitSubexpression(node.target, typeProvider.objectType);
+      var writeElement = node.staticElement;
+      DartType indexContext;
+      DartType writeType;
+      DartType readType;
+      if (writeElement == null) {
+        indexContext = UnknownInferredType.instance;
+        writeType = typeProvider.dynamicType;
+        readType = isCompound ? typeProvider.dynamicType : null;
+      } else {
+        var writerType =
+            _computeMigratedType(writeElement, targetType: targetType)
+                as FunctionType;
+        writeType = writerType.parameters[1].type;
+        if (isCompound) {
+          var readerType = _computeMigratedType(
+              node.auxiliaryElements.staticElement,
+              targetType: targetType) as FunctionType;
+          readType = readerType.returnType;
+          indexContext = readerType.parameters[0].type;
+        } else {
+          indexContext = writerType.parameters[0].type;
+        }
+      }
+      visitSubexpression(node.index, indexContext);
       return AssignmentTargetInfo(readType, writeType);
+    } else if (node is PropertyAccess) {
+      return _handleAssignmentTargetForPropertyAccess(node, node.target,
+          node.propertyName, isNullAwareToken(node.operator.type), isCompound);
+    } else if (node is PrefixedIdentifier) {
+      if (node.prefix.staticElement is ImportElement) {
+        // TODO(paulberry)
+        throw UnimplementedError(
+            'TODO(paulberry): PrefixedIdentifier with a prefix');
+      } else {
+        return _handleAssignmentTargetForPropertyAccess(
+            node, node.prefix, node.identifier, false, isCompound);
+      }
     } else {
       throw UnimplementedError('TODO(paulberry)');
     }
@@ -179,42 +234,38 @@
     switch (operatorType) {
       case TokenType.BANG_EQ:
       case TokenType.EQ_EQ:
-        visitSubexpression(leftOperand, _typeProvider.dynamicType);
-        visitSubexpression(rightOperand, _typeProvider.dynamicType);
-        if (leftOperand is SimpleIdentifier && rightOperand is NullLiteral) {
-          var leftElement = leftOperand.staticElement;
-          if (leftElement is PromotableElement) {
-            _flowAnalysis.conditionEqNull(node, leftElement,
-                notEqual: operatorType == TokenType.BANG_EQ);
-          }
-        }
-        return _typeProvider.boolType;
+        visitSubexpression(leftOperand, typeProvider.dynamicType);
+        _flowAnalysis.equalityOp_rightBegin(leftOperand);
+        visitSubexpression(rightOperand, typeProvider.dynamicType);
+        _flowAnalysis.equalityOp_end(node, rightOperand,
+            notEqual: operatorType == TokenType.BANG_EQ);
+        return typeProvider.boolType;
       case TokenType.AMPERSAND_AMPERSAND:
       case TokenType.BAR_BAR:
         var isAnd = operatorType == TokenType.AMPERSAND_AMPERSAND;
-        visitSubexpression(leftOperand, _typeProvider.boolType);
+        visitSubexpression(leftOperand, typeProvider.boolType);
         _flowAnalysis.logicalBinaryOp_rightBegin(leftOperand, isAnd: isAnd);
-        visitSubexpression(rightOperand, _typeProvider.boolType);
+        visitSubexpression(rightOperand, typeProvider.boolType);
         _flowAnalysis.logicalBinaryOp_end(node, rightOperand, isAnd: isAnd);
-        return _typeProvider.boolType;
+        return typeProvider.boolType;
       case TokenType.QUESTION_QUESTION:
         // If `a ?? b` is used in a non-nullable context, we don't want to
         // migrate it to `(a ?? b)!`.  We want to migrate it to `a ?? b!`.
-        // TODO(paulberry): once flow analysis supports `??`, integrate it here.
-        // See https://github.com/dart-lang/sdk/issues/38680
         var leftType = visitSubexpression(node.leftOperand,
             _typeSystem.makeNullable(_contextType as TypeImpl));
+        _flowAnalysis.ifNullExpression_rightBegin();
         var rightType = visitSubexpression(node.rightOperand, _contextType);
+        _flowAnalysis.ifNullExpression_end();
         return _typeSystem.leastUpperBound(
             _typeSystem.promoteToNonNull(leftType as TypeImpl), rightType);
       default:
         var targetType =
-            visitSubexpression(leftOperand, _typeProvider.objectType);
+            visitSubexpression(leftOperand, typeProvider.objectType);
         DartType contextType;
         DartType returnType;
         if (staticElement == null) {
-          contextType = _typeProvider.dynamicType;
-          returnType = _typeProvider.dynamicType;
+          contextType = typeProvider.dynamicType;
+          returnType = typeProvider.dynamicType;
         } else {
           var methodType =
               _computeMigratedType(staticElement, targetType: targetType)
@@ -228,9 +279,95 @@
   }
 
   @override
-  DartType visitExpression(Expression node) {
-    // Every expression type needs its own visit method.
-    throw UnimplementedError('No visit method for ${node.runtimeType}');
+  DartType visitBlock(Block node) {
+    for (var statement in node.statements) {
+      statement.accept(this);
+    }
+    return null;
+  }
+
+  @override
+  DartType visitConditionalExpression(ConditionalExpression node) {
+    visitSubexpression(node.condition, typeProvider.boolType);
+    _flowAnalysis.conditional_thenBegin(node.condition);
+    var thenType = visitSubexpression(node.thenExpression, _contextType);
+    _flowAnalysis.conditional_elseBegin(node.thenExpression);
+    var elseType = visitSubexpression(node.elseExpression, _contextType);
+    _flowAnalysis.conditional_end(node, node.elseExpression);
+    return _typeSystem.leastUpperBound(thenType, elseType);
+  }
+
+  @override
+  DartType visitExpressionStatement(ExpressionStatement node) {
+    visitSubexpression(node.expression, UnknownInferredType.instance);
+    return null;
+  }
+
+  @override
+  DartType visitIfStatement(IfStatement node) {
+    visitSubexpression(node.condition, typeProvider.boolType);
+    _flowAnalysis.ifStatement_thenBegin(node.condition);
+    node.thenStatement.accept(this);
+    bool hasElse = node.elseStatement != null;
+    if (hasElse) {
+      _flowAnalysis.ifStatement_elseBegin();
+      node.elseStatement.accept(this);
+    }
+    _flowAnalysis.ifStatement_end(hasElse);
+    return null;
+  }
+
+  @override
+  DartType visitIndexExpression(IndexExpression node) {
+    var target = node.target;
+    var staticElement = node.staticElement;
+    var index = node.index;
+    var targetType = visitSubexpression(target, typeProvider.objectType);
+    DartType contextType;
+    DartType returnType;
+    if (staticElement == null) {
+      contextType = typeProvider.dynamicType;
+      returnType = typeProvider.dynamicType;
+    } else {
+      var methodType =
+          _computeMigratedType(staticElement, targetType: targetType)
+              as FunctionType;
+      contextType = methodType.parameters[0].type;
+      returnType = methodType.returnType;
+    }
+    visitSubexpression(index, contextType);
+    return returnType;
+  }
+
+  @override
+  DartType visitListLiteral(ListLiteral node) {
+    DartType contextType;
+    var typeArguments = node.typeArguments;
+    if (typeArguments != null) {
+      var typeArgumentTypes = _visitTypeArgumentList(typeArguments);
+      if (typeArgumentTypes.isNotEmpty) {
+        contextType = typeArgumentTypes[0];
+      } else {
+        contextType = UnknownInferredType.instance;
+      }
+    } else {
+      throw UnimplementedError(
+          'TODO(paulberry): extract from surrounding context');
+    }
+    for (var listElement in node.elements) {
+      if (listElement is Expression) {
+        visitSubexpression(listElement, contextType);
+      } else {
+        throw UnimplementedError(
+            'TODO(paulberry): handle spread and control flow');
+      }
+    }
+    if (typeArguments != null) {
+      return typeProvider.listType2(contextType);
+    } else {
+      throw UnimplementedError(
+          'TODO(paulberry): infer list type based on contents');
+    }
   }
 
   @override
@@ -247,8 +384,82 @@
   }
 
   @override
+  DartType visitNode(AstNode node) {
+    // Every node type needs its own visit method.
+    throw UnimplementedError('No visit method for ${node.runtimeType}');
+  }
+
+  @override
+  DartType visitNullLiteral(NullLiteral node) {
+    _flowAnalysis.nullLiteral(node);
+    return typeProvider.nullType;
+  }
+
+  @override
   DartType visitParenthesizedExpression(ParenthesizedExpression node) {
-    return node.expression.accept(this);
+    var result = node.expression.accept(this);
+    _flowAnalysis.parenthesizedExpression(node, node.expression);
+    return result;
+  }
+
+  @override
+  DartType visitPostfixExpression(PostfixExpression node) {
+    if (node.operator.type == TokenType.BANG) {
+      throw UnimplementedError(
+          'TODO(paulberry): re-migration of already migrated code not '
+          'supported yet');
+    } else {
+      var targetInfo = visitAssignmentTarget(node.operand, true);
+      _handleIncrementOrDecrement(node.staticElement, targetInfo, node);
+      return targetInfo.readType;
+    }
+  }
+
+  @override
+  DartType visitPrefixedIdentifier(PrefixedIdentifier node) {
+    if (node.prefix.staticElement is ImportElement) {
+      // TODO(paulberry)
+      throw UnimplementedError(
+          'TODO(paulberry): PrefixedIdentifier with a prefix');
+    } else {
+      return _handlePropertyAccess(node, node.prefix, node.identifier, false);
+    }
+  }
+
+  @override
+  DartType visitPrefixExpression(PrefixExpression node) {
+    var operand = node.operand;
+    switch (node.operator.type) {
+      case TokenType.BANG:
+        visitSubexpression(operand, typeProvider.boolType);
+        _flowAnalysis.logicalNot_end(node, operand);
+        return typeProvider.boolType;
+      case TokenType.MINUS:
+      case TokenType.TILDE:
+        var targetType = visitSubexpression(operand, typeProvider.objectType);
+        var staticElement = node.staticElement;
+        if (staticElement == null) {
+          return typeProvider.dynamicType;
+        } else {
+          var methodType =
+              _computeMigratedType(staticElement, targetType: targetType)
+                  as FunctionType;
+          return methodType.returnType;
+        }
+        break;
+      case TokenType.PLUS_PLUS:
+      case TokenType.MINUS_MINUS:
+        return _handleIncrementOrDecrement(
+            node.staticElement, visitAssignmentTarget(operand, true), node);
+      default:
+        throw StateError('Unexpected prefix operator: ${node.operator}');
+    }
+  }
+
+  @override
+  DartType visitPropertyAccess(PropertyAccess node) {
+    return _handlePropertyAccess(node, node.target, node.propertyName,
+        isNullAwareToken(node.operator.type));
   }
 
   @override
@@ -256,9 +467,9 @@
     assert(!node.inSetterContext(),
         'Should use visitAssignmentTarget in setter contexts');
     var element = node.staticElement;
-    if (element == null) return _typeProvider.dynamicType;
+    if (element == null) return typeProvider.dynamicType;
     if (element is PromotableElement) {
-      var promotedType = _flowAnalysis.promotedType(element);
+      var promotedType = _flowAnalysis.variableRead(node, element);
       if (promotedType != null) return promotedType;
     }
     return _computeMigratedType(element);
@@ -272,6 +483,7 @@
       var type = subexpression.accept(this);
       if (_doesAssignmentNeedCheck(from: type, to: contextType)) {
         addNullCheck(subexpression);
+        _flowAnalysis.nonNullAssert_end(subexpression);
         return _typeSystem.promoteToNonNull(type as TypeImpl);
       } else {
         return type;
@@ -281,6 +493,64 @@
     }
   }
 
+  @override
+  DartType visitThrowExpression(ThrowExpression node) {
+    visitSubexpression(node.expression, typeProvider.objectType);
+    _flowAnalysis.handleExit();
+    return typeProvider.neverType;
+  }
+
+  @override
+  DartType visitTypeName(TypeName node) {
+    var decoratedType = _variables.decoratedTypeAnnotation(source, node);
+    assert(decoratedType != null);
+    List<DartType> arguments = [];
+    if (node.typeArguments != null) {
+      for (var argument in node.typeArguments.arguments) {
+        arguments.add(argument.accept(this));
+      }
+    }
+    if (decoratedType.type.isDynamic || decoratedType.type.isVoid) {
+      // Already nullable.  Nothing to do.
+      return decoratedType.type;
+    } else {
+      var element = decoratedType.type.element as ClassElement;
+      bool isNullable = decoratedType.node.isNullable;
+      if (isNullable) {
+        addNullable(node);
+      }
+      return InterfaceTypeImpl.explicit(element, arguments,
+          nullabilitySuffix:
+              isNullable ? NullabilitySuffix.question : NullabilitySuffix.none);
+    }
+  }
+
+  @override
+  DartType visitVariableDeclarationList(VariableDeclarationList node) {
+    node.metadata.accept(this);
+    DartType contextType;
+    var typeAnnotation = node.type;
+    if (typeAnnotation != null) {
+      contextType = typeAnnotation.accept(this);
+      assert(contextType != null);
+    } else {
+      contextType = UnknownInferredType.instance;
+    }
+    for (var variable in node.variables) {
+      if (variable.initializer != null) {
+        visitSubexpression(variable.initializer, contextType);
+      }
+    }
+    return null;
+  }
+
+  @override
+  DartType visitVariableDeclarationStatement(
+      VariableDeclarationStatement node) {
+    node.variables.accept(this);
+    return null;
+  }
+
   /// Computes the type that [element] will have after migration.
   ///
   /// If [targetType] is present, and [element] is a class member, it is the
@@ -295,23 +565,23 @@
     }
     DartType type;
     if (baseElement is ClassElement || baseElement is TypeParameterElement) {
-      return _typeProvider.typeType;
+      return typeProvider.typeType;
     } else if (baseElement is PropertyAccessorElement) {
       if (baseElement.isSynthetic) {
         type = _variables
             .decoratedElementType(baseElement.variable)
-            .toFinalType(_typeProvider);
+            .toFinalType(typeProvider);
       } else {
         var functionType = _variables.decoratedElementType(baseElement);
         var decoratedType = baseElement.isGetter
             ? functionType.returnType
             : functionType.positionalParameters[0];
-        type = decoratedType.toFinalType(_typeProvider);
+        type = decoratedType.toFinalType(typeProvider);
       }
     } else {
       type = _variables
           .decoratedElementType(baseElement)
-          .toFinalType(_typeProvider);
+          .toFinalType(typeProvider);
     }
     if (targetType is InterfaceType && targetType.typeArguments.isNotEmpty) {
       var superclass = baseElement.enclosingElement as ClassElement;
@@ -319,7 +589,7 @@
       if (class_ != superclass) {
         var supertype = _decoratedClassHierarchy
             .getDecoratedSupertype(class_, superclass)
-            .toFinalType(_typeProvider) as InterfaceType;
+            .toFinalType(typeProvider) as InterfaceType;
         type = Substitution.fromInterfaceType(supertype).substituteType(type);
       }
       return substitute(type, {
@@ -353,6 +623,75 @@
       return type;
     }
   }
+
+  AssignmentTargetInfo _handleAssignmentTargetForPropertyAccess(
+      Expression node,
+      Expression target,
+      SimpleIdentifier propertyName,
+      bool isNullAware,
+      bool isCompound) {
+    var targetType = visitSubexpression(target,
+        isNullAware ? typeProvider.dynamicType : typeProvider.objectType);
+    var writeElement = propertyName.staticElement;
+    DartType writeType;
+    DartType readType;
+    if (writeElement == null) {
+      writeType = typeProvider.dynamicType;
+      readType = isCompound ? typeProvider.dynamicType : null;
+    } else {
+      writeType = _computeMigratedType(writeElement, targetType: targetType);
+      if (isCompound) {
+        readType = _computeMigratedType(
+            propertyName.auxiliaryElements.staticElement,
+            targetType: targetType);
+      }
+      return AssignmentTargetInfo(readType, writeType);
+    }
+    return AssignmentTargetInfo(readType, writeType);
+  }
+
+  DartType _handleIncrementOrDecrement(MethodElement combiner,
+      AssignmentTargetInfo targetInfo, Expression node) {
+    DartType combinedType;
+    if (combiner == null) {
+      combinedType = typeProvider.dynamicType;
+    } else {
+      if (_typeSystem.isNullable(targetInfo.readType)) {
+        addProblem(node, const CompoundAssignmentReadNullable());
+      }
+      var combinerType = _computeMigratedType(combiner) as FunctionType;
+      combinedType = _fixNumericTypes(combinerType.returnType, node.staticType);
+    }
+    if (_doesAssignmentNeedCheck(
+        from: combinedType, to: targetInfo.writeType)) {
+      addProblem(node, const CompoundAssignmentCombinedNullable());
+      combinedType = _typeSystem.promoteToNonNull(combinedType as TypeImpl);
+    }
+    return combinedType;
+  }
+
+  DartType _handlePropertyAccess(Expression node, Expression target,
+      SimpleIdentifier propertyName, bool isNullAware) {
+    var staticElement = propertyName.staticElement;
+    var isNullOk = isNullAware || isDeclaredOnObject(propertyName.name);
+    var targetType = visitSubexpression(
+        target, isNullOk ? typeProvider.dynamicType : typeProvider.objectType);
+    if (staticElement == null) {
+      return typeProvider.dynamicType;
+    } else {
+      var type = _computeMigratedType(staticElement, targetType: targetType);
+      if (isNullAware) {
+        return _typeSystem.makeNullable(type as TypeImpl);
+      } else {
+        return type;
+      }
+    }
+  }
+
+  /// Visits all the type arguments in a [TypeArgumentList] and returns the
+  /// types they ger migrated to.
+  List<DartType> _visitTypeArgumentList(TypeArgumentList arguments) =>
+      [for (var argument in arguments.arguments) argument.accept(this)];
 }
 
 /// Common supertype for problems reported by [FixBuilder.addProblem].
diff --git a/pkg/nnbd_migration/lib/src/node_builder.dart b/pkg/nnbd_migration/lib/src/node_builder.dart
index 66a9fc2..85cdb6e 100644
--- a/pkg/nnbd_migration/lib/src/node_builder.dart
+++ b/pkg/nnbd_migration/lib/src/node_builder.dart
@@ -7,7 +7,6 @@
 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/handle.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -649,9 +648,6 @@
         decoratedSupertype = supertype.accept(this);
       }
       var class_ = (decoratedSupertype.type as InterfaceType).element;
-      if (class_ is ClassElementHandle) {
-        class_ = (class_ as ClassElementHandle).actualElement;
-      }
       decoratedSupertypes[class_] = decoratedSupertype;
     }
     _variables.recordDecoratedDirectSupertypes(
diff --git a/pkg/nnbd_migration/lib/src/utilities/resolution_utils.dart b/pkg/nnbd_migration/lib/src/utilities/resolution_utils.dart
new file mode 100644
index 0000000..897d731
--- /dev/null
+++ b/pkg/nnbd_migration/lib/src/utilities/resolution_utils.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.
+
+import 'package:analyzer/dart/ast/token.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+
+/// This mixin provides utilities that are useful to visitors implementing
+/// resolution-like behaviors.
+mixin ResolutionUtils {
+  List<String> _objectGetNames;
+
+  TypeProvider get typeProvider;
+
+  /// Determines whether the given getter or method name is declared on
+  /// `Object` (and is hence valid to call on a nullable type).
+  bool isDeclaredOnObject(String name) =>
+      (_objectGetNames ??= _computeObjectGetNames()).contains(name);
+
+  /// Determines whether the given property/method access token is null-aware.
+  bool isNullAwareToken(TokenType tokenType) {
+    switch (tokenType) {
+      case TokenType.PERIOD:
+      case TokenType.PERIOD_PERIOD:
+        return false;
+      case TokenType.QUESTION_PERIOD:
+        return true;
+      default:
+        throw new UnimplementedError(
+            'Unexpected token passed to isNullAwareToken: $tokenType');
+    }
+  }
+
+  List<String> _computeObjectGetNames() {
+    var result = <String>[];
+    var objectClass = typeProvider.objectType.element;
+    for (var accessor in objectClass.accessors) {
+      assert(accessor.isGetter);
+      assert(!accessor.name.startsWith('_'));
+      result.add(accessor.name);
+    }
+    for (var method in objectClass.methods) {
+      assert(!method.name.startsWith('_'));
+      result.add(method.name);
+    }
+    return result;
+  }
+}
diff --git a/pkg/nnbd_migration/lib/src/variables.dart b/pkg/nnbd_migration/lib/src/variables.dart
index 5266dec..057fc52 100644
--- a/pkg/nnbd_migration/lib/src/variables.dart
+++ b/pkg/nnbd_migration/lib/src/variables.dart
@@ -5,7 +5,6 @@
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/dart/element/type.dart';
-import 'package:analyzer/src/dart/element/handle.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/source.dart';
@@ -43,7 +42,6 @@
   @override
   Map<ClassElement, DecoratedType> decoratedDirectSupertypes(
       ClassElement class_) {
-    assert(class_ is! ClassElementHandle);
     return _decoratedDirectSupertypes[class_] ??=
         _decorateDirectSupertypes(class_);
   }
@@ -115,13 +113,6 @@
   @override
   void recordDecoratedDirectSupertypes(ClassElement class_,
       Map<ClassElement, DecoratedType> decoratedDirectSupertypes) {
-    assert(() {
-      assert(class_ is! ClassElementHandle);
-      for (var key in decoratedDirectSupertypes.keys) {
-        assert(key is! ClassElementHandle);
-      }
-      return true;
-    }());
     _decoratedDirectSupertypes[class_] = decoratedDirectSupertypes;
   }
 
@@ -210,9 +201,6 @@
         in _alreadyMigratedCodeDecorator.getImmediateSupertypes(class_)) {
       assert(identical(decoratedSupertype.node, _graph.never));
       var class_ = (decoratedSupertype.type as InterfaceType).element;
-      if (class_ is ClassElementHandle) {
-        class_ = (class_ as ClassElementHandle).actualElement;
-      }
       result[class_] = decoratedSupertype;
     }
     return result;
diff --git a/pkg/nnbd_migration/test/edge_builder_test.dart b/pkg/nnbd_migration/test/edge_builder_test.dart
index a7db1db..05fc775 100644
--- a/pkg/nnbd_migration/test/edge_builder_test.dart
+++ b/pkg/nnbd_migration/test/edge_builder_test.dart
@@ -4221,7 +4221,7 @@
     assertNullCheck(use, assertEdge(declaration, never, hard: true));
 
     var returnType = decoratedTypeAnnotation('int f').node;
-    assertEdge(never, returnType, hard: false);
+    assertEdge(declaration, returnType, hard: false);
   }
 
   test_postfixExpression_plusPlus() async {
@@ -4236,7 +4236,37 @@
     assertNullCheck(use, assertEdge(declaration, never, hard: true));
 
     var returnType = decoratedTypeAnnotation('int f').node;
-    assertEdge(never, returnType, hard: false);
+    assertEdge(declaration, returnType, hard: false);
+  }
+
+  test_postfixExpression_plusPlus_dynamic() async {
+    await analyze('''
+Object f(dynamic d) {
+  return d++;
+}
+''');
+    assertEdge(decoratedTypeAnnotation('dynamic d').node,
+        decoratedTypeAnnotation('Object f').node,
+        hard: false);
+  }
+
+  test_postfixExpression_plusPlus_substituted() async {
+    await analyze('''
+abstract class C<T> {
+  C<T> operator+(int x);
+}
+C<int> f(C<int> c) {
+  return c++;
+}
+''');
+
+    var cType = decoratedTypeAnnotation('C<int> c');
+    var returnType = decoratedTypeAnnotation('C<int> f');
+    assertNullCheck(
+        checkExpression('c++'), assertEdge(cType.node, never, hard: true));
+    assertEdge(cType.node, returnType.node, hard: false);
+    assertEdge(cType.typeArguments[0].node, returnType.typeArguments[0].node,
+        hard: false);
   }
 
   test_prefixedIdentifier_field_type() async {
@@ -4339,6 +4369,16 @@
     assertEdge(never, return_f, hard: false);
   }
 
+  test_prefixExpression_bang_dynamic() async {
+    await analyze('''
+Object f(dynamic d) {
+  return !d;
+}
+''');
+    var return_f = decoratedTypeAnnotation('Object f').node;
+    assertEdge(never, return_f, hard: false);
+  }
+
   test_prefixExpression_minus() async {
     await analyze('''
 abstract class C {
@@ -4353,6 +4393,35 @@
         assertEdge(decoratedTypeAnnotation('C c').node, never, hard: true));
   }
 
+  test_prefixExpression_minus_dynamic() async {
+    await analyze('''
+Object test(dynamic d) => -d;
+''');
+    assertEdge(always, decoratedTypeAnnotation('Object test').node,
+        hard: false);
+    assertEdge(decoratedTypeAnnotation('dynamic d').node, never, hard: true);
+  }
+
+  test_prefixExpression_minus_substituted() async {
+    await analyze('''
+abstract class C<T> {
+  List<T> operator-();
+}
+List<int> test(C<int> c) => -c/*check*/;
+''');
+    var operatorReturnType = decoratedTypeAnnotation('List<T> operator');
+    var cType = decoratedTypeAnnotation('C<int> c');
+    var testReturnType = decoratedTypeAnnotation('List<int> test');
+    assertEdge(operatorReturnType.node, testReturnType.node, hard: false);
+    assertNullCheck(checkExpression('c/*check*/'),
+        assertEdge(cType.node, never, hard: true));
+    assertEdge(
+        substitutionNode(cType.typeArguments[0].node,
+            operatorReturnType.typeArguments[0].node),
+        testReturnType.typeArguments[0].node,
+        hard: false);
+  }
+
   test_prefixExpression_minusMinus() async {
     await analyze('''
 int f(int i) {
@@ -4383,6 +4452,35 @@
     assertEdge(never, returnType, hard: false);
   }
 
+  test_prefixExpression_plusPlus_dynamic() async {
+    await analyze('''
+Object f(dynamic d) {
+  return ++d;
+}
+''');
+    var returnType = decoratedTypeAnnotation('Object f').node;
+    assertEdge(always, returnType, hard: false);
+  }
+
+  test_prefixExpression_plusPlus_substituted() async {
+    await analyze('''
+abstract class C<T> {
+  C<T> operator+(int i);
+}
+C<int> f(C<int> x) => ++x;
+    ''');
+    var xType = decoratedTypeAnnotation('C<int> x');
+    var plusReturnType = decoratedTypeAnnotation('C<T> operator');
+    var fReturnType = decoratedTypeAnnotation('C<int> f');
+    assertEdge(xType.node, never, hard: true);
+    assertEdge(plusReturnType.node, fReturnType.node, hard: false);
+    assertEdge(
+        substitutionNode(
+            xType.typeArguments[0].node, plusReturnType.typeArguments[0].node),
+        fReturnType.typeArguments[0].node,
+        hard: false);
+  }
+
   test_propertyAccess_dynamic() async {
     await analyze('''
 class C {
@@ -4540,6 +4638,46 @@
         hard: true);
   }
 
+  test_return_from_async_closureBody_future() async {
+    await analyze('''
+Future<int> f() {
+  return () async {
+    return g();
+  }();
+}
+int g() => 1;
+''');
+    assertEdge(
+        decoratedTypeAnnotation('int g').node,
+        assertEdge(anyNode, decoratedTypeAnnotation('int>').node, hard: false)
+            .sourceNode,
+        hard: false);
+  }
+
+  test_return_from_async_closureExpression_future() async {
+    await analyze('''
+Future<int> Function() f() {
+  return () async => g();
+}
+int g() => 1;
+''');
+    assertEdge(
+        decoratedTypeAnnotation('int g').node,
+        assertEdge(anyNode, decoratedTypeAnnotation('int>').node, hard: false)
+            .sourceNode,
+        hard: false);
+  }
+
+  test_return_from_async_expressionBody_future() async {
+    await analyze('''
+Future<int> f() async => g();
+int g() => 1;
+''');
+    assertEdge(decoratedTypeAnnotation('int g').node,
+        decoratedTypeAnnotation('int>').node,
+        hard: false);
+  }
+
   test_return_from_async_future() async {
     await analyze('''
 Future<int> f() async {
@@ -4547,7 +4685,19 @@
 }
 int g() => 1;
 ''');
-    // No assertions; just checking that it doesn't crash.
+    assertEdge(decoratedTypeAnnotation('int g').node,
+        decoratedTypeAnnotation('int>').node,
+        hard: false);
+  }
+
+  test_return_from_async_future_void() async {
+    await analyze('''
+Future<void> f() async {
+  return;
+}
+int g() => 1;
+''');
+    assertNoEdge(always, decoratedTypeAnnotation('Future').node);
   }
 
   test_return_from_async_futureOr() async {
diff --git a/pkg/nnbd_migration/test/fix_builder_test.dart b/pkg/nnbd_migration/test/fix_builder_test.dart
index c2096b2..9019de2 100644
--- a/pkg/nnbd_migration/test/fix_builder_test.dart
+++ b/pkg/nnbd_migration/test/fix_builder_test.dart
@@ -8,6 +8,7 @@
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/type_system.dart';
 import 'package:nnbd_migration/src/decorated_class_hierarchy.dart';
 import 'package:nnbd_migration/src/fix_builder.dart';
@@ -235,6 +236,328 @@
     visitSubexpression(findNode.binary('&&'), 'bool');
   }
 
+  test_assignmentTarget_indexExpression_compound_dynamic() async {
+    await analyze('''
+_f(dynamic d, int/*?*/ i) => d[i] += 0;
+''');
+    visitAssignmentTarget(findNode.index('d[i]'), 'dynamic', 'dynamic');
+  }
+
+  test_assignmentTarget_indexExpression_compound_simple() async {
+    await analyze('''
+class _C {
+  int operator[](String s) => 1;
+  void operator[]=(String s, num n) {}
+}
+_f(_C c) => c['foo'] += 0;
+''');
+    visitAssignmentTarget(findNode.index('c['), 'int', 'num');
+  }
+
+  test_assignmentTarget_indexExpression_compound_simple_check_lhs() async {
+    await analyze('''
+class _C {
+  int operator[](String s) => 1;
+  void operator[]=(String s, num n) {}
+}
+_f(_C/*?*/ c) => c['foo'] += 0;
+''');
+    visitAssignmentTarget(findNode.index('c['), 'int', 'num',
+        nullChecked: {findNode.simple('c[')});
+  }
+
+  test_assignmentTarget_indexExpression_compound_simple_check_rhs() async {
+    await analyze('''
+class _C {
+  int operator[](String/*!*/ s) => 1;
+  void operator[]=(String/*?*/ s, num n) {}
+}
+_f(_C c, String/*?*/ s) => c[s] += 0;
+''');
+    visitAssignmentTarget(findNode.index('c['), 'int', 'num',
+        nullChecked: {findNode.simple('s]')});
+  }
+
+  test_assignmentTarget_indexExpression_compound_substituted() async {
+    await analyze('''
+class _C<T, U> {
+  T operator[](U u) => throw 'foo';
+  void operator[]=(U u, T t) {}
+}
+_f(_C<int, String> c) => c['foo'] += 1;
+''');
+    visitAssignmentTarget(findNode.index('c['), 'int', 'int');
+  }
+
+  test_assignmentTarget_indexExpression_compound_substituted_check_rhs() async {
+    await analyze('''
+class _C<T, U> {
+  T operator[](U u) => throw 'foo';
+  void operator[]=(U/*?*/ u, T t) {}
+}
+_f(_C<int, String/*!*/> c, String/*?*/ s) => c[s] += 1;
+''');
+    visitAssignmentTarget(findNode.index('c['), 'int', 'int',
+        nullChecked: {findNode.simple('s]')});
+  }
+
+  test_assignmentTarget_indexExpression_compound_substituted_no_check_rhs() async {
+    await analyze('''
+class _C<T, U> {
+  T operator[](U u) => throw 'foo';
+  void operator[]=(U u, T t) {}
+}
+_f(_C<int, String/*?*/> c, String/*?*/ s) => c[s] += 0;
+''');
+    visitAssignmentTarget(findNode.index('c['), 'int', 'int');
+  }
+
+  test_assignmentTarget_indexExpression_dynamic() async {
+    await analyze('''
+_f(dynamic d, int/*?*/ i) => d[i] = 0;
+''');
+    visitAssignmentTarget(findNode.index('d[i]'), null, 'dynamic');
+  }
+
+  test_assignmentTarget_indexExpression_simple() async {
+    await analyze('''
+class _C {
+  int operator[](String s) => 1;
+  void operator[]=(String s, num n) {}
+}
+_f(_C c) => c['foo'] = 0;
+''');
+    visitAssignmentTarget(findNode.index('c['), null, 'num');
+  }
+
+  test_assignmentTarget_indexExpression_simple_check_lhs() async {
+    await analyze('''
+class _C {
+  int operator[](String s) => 1;
+  void operator[]=(String s, num n) {}
+}
+_f(_C/*?*/ c) => c['foo'] = 0;
+''');
+    visitAssignmentTarget(findNode.index('c['), null, 'num',
+        nullChecked: {findNode.simple('c[')});
+  }
+
+  test_assignmentTarget_indexExpression_simple_check_rhs() async {
+    await analyze('''
+class _C {
+  int operator[](String/*?*/ s) => 1;
+  void operator[]=(String/*!*/ s, num n) {}
+}
+_f(_C c, String/*?*/ s) => c[s] = 0;
+''');
+    visitAssignmentTarget(findNode.index('c['), null, 'num',
+        nullChecked: {findNode.simple('s]')});
+  }
+
+  test_assignmentTarget_indexExpression_substituted() async {
+    await analyze('''
+class _C<T, U> {
+  T operator[](U u) => throw 'foo';
+  void operator[]=(U u, T t) {}
+}
+_f(_C<int, String> c) => c['foo'] = 1;
+''');
+    visitAssignmentTarget(findNode.index('c['), null, 'int');
+  }
+
+  test_assignmentTarget_indexExpression_substituted_check_rhs() async {
+    await analyze('''
+class _C<T, U> {
+  T operator[](U u) => throw 'foo';
+  void operator[]=(U/*?*/ u, T t) {}
+}
+_f(_C<int, String/*!*/> c, String/*?*/ s) => c[s] = 1;
+''');
+    visitAssignmentTarget(findNode.index('c['), null, 'int',
+        nullChecked: {findNode.simple('s]')});
+  }
+
+  test_assignmentTarget_indexExpression_substituted_no_check_rhs() async {
+    await analyze('''
+class _C<T, U> {
+  T operator[](U u) => throw 'foo';
+  void operator[]=(U u, T t) {}
+}
+_f(_C<int, String/*?*/> c, String/*?*/ s) => c[s] = 0;
+''');
+    visitAssignmentTarget(findNode.index('c['), null, 'int');
+  }
+
+  test_assignmentTarget_prefixedIdentifier_dynamic() async {
+    await analyze('''
+Object/*!*/ _f(dynamic d) => d.x += 1;
+''');
+    visitAssignmentTarget(findNode.prefixed('d.x'), 'dynamic', 'dynamic');
+  }
+
+  test_assignmentTarget_propertyAccess_dynamic() async {
+    await analyze('''
+_f(dynamic d) => (d).x += 1;
+''');
+    visitAssignmentTarget(
+        findNode.propertyAccess('(d).x'), 'dynamic', 'dynamic');
+  }
+
+  test_assignmentTarget_propertyAccess_dynamic_notCompound() async {
+    await analyze('''
+_f(dynamic d) => (d).x = 1;
+''');
+    visitAssignmentTarget(findNode.propertyAccess('(d).x'), null, 'dynamic');
+  }
+
+  test_assignmentTarget_propertyAccess_field_nonNullable() async {
+    await analyze('''
+class _C {
+  int/*!*/ x = 0;
+}
+_f(_C c) => (c).x += 1;
+''');
+    visitAssignmentTarget(findNode.propertyAccess('(c).x'), 'int', 'int');
+  }
+
+  test_assignmentTarget_propertyAccess_field_nonNullable_notCompound() async {
+    await analyze('''
+class _C {
+  int/*!*/ x = 0;
+}
+_f(_C c) => (c).x = 1;
+''');
+    visitAssignmentTarget(findNode.propertyAccess('(c).x'), null, 'int');
+  }
+
+  test_assignmentTarget_propertyAccess_field_nullable() async {
+    await analyze('''
+class _C {
+  int/*?*/ x = 0;
+}
+_f(_C c) => (c).x += 1;
+''');
+    visitAssignmentTarget(findNode.propertyAccess('(c).x'), 'int?', 'int?');
+  }
+
+  test_assignmentTarget_propertyAccess_getter_nullable() async {
+    await analyze('''
+abstract class _C {
+  int/*?*/ get x;
+  void set x(num/*?*/ value);
+}
+_f(_C c) => (c).x += 1;
+''');
+    visitAssignmentTarget(findNode.propertyAccess('(c).x'), 'int?', 'num?');
+  }
+
+  test_assignmentTarget_propertyAccess_getter_setter_check_lhs() async {
+    await analyze('''
+abstract class _C {
+  int get x;
+  void set x(num value);
+}
+_f(_C/*?*/ c) => (c).x += 1;
+''');
+    visitAssignmentTarget(findNode.propertyAccess('(c).x'), 'int', 'num',
+        nullChecked: {findNode.parenthesized('(c).x')});
+  }
+
+  test_assignmentTarget_propertyAccess_getter_setter_nonNullable() async {
+    await analyze('''
+abstract class _C {
+  int/*!*/ get x;
+  void set x(num/*!*/ value);
+}
+_f(_C c) => (c).x += 1;
+''');
+    visitAssignmentTarget(findNode.propertyAccess('(c).x'), 'int', 'num');
+  }
+
+  test_assignmentTarget_propertyAccess_nullAware_dynamic() async {
+    await analyze('''
+_f(dynamic d) => d?.x += 1;
+''');
+    visitAssignmentTarget(
+        findNode.propertyAccess('d?.x'), 'dynamic', 'dynamic');
+  }
+
+  test_assignmentTarget_propertyAccess_nullAware_field_nonNullable() async {
+    await analyze('''
+class _C {
+  int/*!*/ x = 0;
+}
+_f(_C/*?*/ c) => c?.x += 1;
+''');
+    visitAssignmentTarget(findNode.propertyAccess('c?.x'), 'int', 'int');
+  }
+
+  test_assignmentTarget_propertyAccess_nullAware_field_nullable() async {
+    await analyze('''
+class _C {
+  int/*?*/ x = 0;
+}
+_f(_C/*?*/ c) => c?.x += 1;
+''');
+    visitAssignmentTarget(findNode.propertyAccess('c?.x'), 'int?', 'int?');
+  }
+
+  test_assignmentTarget_propertyAccess_nullAware_getter_setter_nonNullable() async {
+    await analyze('''
+abstract class _C {
+  int/*!*/ get x;
+  void set x(num/*!*/ value);
+}
+_f(_C/*?*/ c) => c?.x += 1;
+''');
+    visitAssignmentTarget(findNode.propertyAccess('c?.x'), 'int', 'num');
+  }
+
+  test_assignmentTarget_propertyAccess_nullAware_getter_setter_nullable() async {
+    await analyze('''
+abstract class _C {
+  int/*?*/ get x;
+  void set x(num/*?*/ value);
+}
+_f(_C/*?*/ c) => c?.x += 1;
+''');
+    visitAssignmentTarget(findNode.propertyAccess('c?.x'), 'int?', 'num?');
+  }
+
+  test_assignmentTarget_propertyAccess_nullAware_substituted() async {
+    await analyze('''
+abstract class _C<T> {
+  _E<T> get x;
+  void set x(_D<T> value);
+}
+class _D<T> implements Iterable<T> {
+  noSuchMethod(invocation) => super.noSuchMethod(invocation);
+  _D<T> operator+(int i) => this;
+}
+class _E<T> extends _D<T> {}
+_f(_C<int>/*?*/ c) => c?.x += 1;
+''');
+    visitAssignmentTarget(
+        findNode.propertyAccess('c?.x'), '_E<int>', '_D<int>');
+  }
+
+  test_assignmentTarget_propertyAccess_substituted() async {
+    await analyze('''
+abstract class _C<T> {
+  _E<T> get x;
+  void set x(_D<T> value);
+}
+class _D<T> implements Iterable<T> {
+  noSuchMethod(invocation) => super.noSuchMethod(invocation);
+  _D<T> operator+(int i) => this;
+}
+class _E<T> extends _D<T> {}
+_f(_C<int> c) => (c).x += 1;
+''');
+    visitAssignmentTarget(
+        findNode.propertyAccess('(c).x'), '_E<int>', '_D<int>');
+  }
+
   test_assignmentTarget_simpleIdentifier_field_generic() async {
     await analyze('''
 abstract class _C<T> {
@@ -337,7 +660,7 @@
   _f() => x = 0;
 }
 ''');
-    visitAssignmentTarget(findNode.simple('x '), 'int?', 'int?');
+    visitAssignmentTarget(findNode.simple('x '), null, 'int?');
   }
 
   test_binaryExpression_ampersand_ampersand() async {
@@ -419,6 +742,17 @@
     visitSubexpression(findNode.binary('??'), 'num?');
   }
 
+  test_binaryExpression_question_question_flow() async {
+    await analyze('''
+_f(int/*?*/ x, int/*?*/ y) =>
+    <dynamic>[x ?? (y != null ? 1 : throw 'foo'), y + 1];
+''');
+    // The null check on the RHS of the `??` doesn't promote, because it is not
+    // guaranteed to execute.
+    visitSubexpression(findNode.listLiteral('['), 'List<dynamic>',
+        nullChecked: {findNode.simple('y +')});
+  }
+
   test_binaryExpression_question_question_nullChecked() async {
     await analyze('''
 Object/*!*/ _f(int/*?*/ x, double/*?*/ y) {
@@ -508,6 +842,19 @@
     visitSubexpression(findNode.binary('c +'), 'int');
   }
 
+  test_block() async {
+    await analyze('''
+_f(int/*?*/ x, int/*?*/ y) {
+  { // block
+    x + 1;
+    y + 1;
+  }
+}
+''');
+    visitStatement(findNode.statement('{ // block'),
+        nullChecked: {findNode.simple('x + 1'), findNode.simple('y + 1')});
+  }
+
   test_booleanLiteral() async {
     await analyze('''
 f() => true;
@@ -515,6 +862,55 @@
     visitSubexpression(findNode.booleanLiteral('true'), 'bool');
   }
 
+  test_conditionalExpression_flow_as_condition() async {
+    await analyze('''
+_f(bool x, int/*?*/ y) => (x ? y != null : y != null) ? y + 1 : 0;
+''');
+    // No explicit check needs to be added to `y + 1`, because both arms of the
+    // conditional can only be true if `y != null`.
+    visitSubexpression(findNode.conditionalExpression('y + 1'), 'int');
+  }
+
+  test_conditionalExpression_flow_condition() async {
+    await analyze('''
+_f(bool/*?*/ x) => x ? (x && true) : (x && true);
+''');
+    // No explicit check needs to be added to either `x && true`, because there
+    // is already an explicit null check inserted for the condition.
+    visitSubexpression(findNode.conditionalExpression('x ?'), 'bool',
+        nullChecked: {findNode.simple('x ?')});
+  }
+
+  test_conditionalExpression_flow_then_else() async {
+    await analyze('''
+_f(bool x, bool/*?*/ y) => (x ? (y && true) : (y && true)) && y;
+''');
+    // No explicit check needs to be added to the final reference to `y`,
+    // because null checks are added to the "then" and "else" branches promoting
+    // y.
+    visitSubexpression(findNode.binary('&& y'), 'bool', nullChecked: {
+      findNode.simple('y && true) '),
+      findNode.simple('y && true))')
+    });
+  }
+
+  test_conditionalExpression_lub() async {
+    await analyze('''
+_f(bool b) => b ? 1 : 1.0;
+''');
+    visitSubexpression(findNode.conditionalExpression('1.0'), 'num');
+  }
+
+  test_conditionalExpression_throw_promotes() async {
+    await analyze('''
+_f(int/*?*/ x) =>
+    <dynamic>[(x != null ? 1 : throw 'foo'), x + 1];
+''');
+    // No null check needs to be added to `x + 1`, because there is already an
+    // explicit null check.
+    visitSubexpression(findNode.listLiteral('['), 'List<dynamic>');
+  }
+
   test_doubleLiteral() async {
     await analyze('''
 f() => 1.0;
@@ -522,6 +918,126 @@
     visitSubexpression(findNode.doubleLiteral('1.0'), 'double');
   }
 
+  test_expressionStatement() async {
+    await analyze('''
+_f(int/*!*/ x, int/*?*/ y) {
+  x = y;
+}
+''');
+    visitStatement(findNode.statement('x = y'),
+        nullChecked: {findNode.simple('y;')});
+  }
+
+  test_ifStatement_flow_promote_in_else() async {
+    await analyze('''
+_f(int/*?*/ x) {
+  if (x == null) {
+    x + 1;
+  } else {
+    x + 2;
+  }
+}
+''');
+    visitStatement(findNode.statement('if'),
+        nullChecked: {findNode.simple('x + 1')});
+  }
+
+  test_ifStatement_flow_promote_in_then() async {
+    await analyze('''
+_f(int/*?*/ x) {
+  if (x != null) {
+    x + 1;
+  } else {
+    x + 2;
+  }
+}
+''');
+    visitStatement(findNode.statement('if'),
+        nullChecked: {findNode.simple('x + 2')});
+  }
+
+  test_ifStatement_flow_promote_in_then_no_else() async {
+    await analyze('''
+_f(int/*?*/ x) {
+  if (x != null) {
+    x + 1;
+  }
+}
+''');
+    visitStatement(findNode.statement('if'));
+  }
+
+  test_indexExpression_dynamic() async {
+    await analyze('''
+Object/*!*/ _f(dynamic d, int/*?*/ i) => d[i];
+''');
+    visitSubexpression(findNode.index('d[i]'), 'dynamic',
+        contextType: objectType);
+  }
+
+  test_indexExpression_simple() async {
+    await analyze('''
+class _C {
+  int operator[](String s) => 1;
+}
+_f(_C c) => c['foo'];
+''');
+    visitSubexpression(findNode.index('c['), 'int');
+  }
+
+  test_indexExpression_simple_check_lhs() async {
+    await analyze('''
+class _C {
+  int operator[](String s) => 1;
+}
+_f(_C/*?*/ c) => c['foo'];
+''');
+    visitSubexpression(findNode.index('c['), 'int',
+        nullChecked: {findNode.simple('c[')});
+  }
+
+  test_indexExpression_simple_check_rhs() async {
+    await analyze('''
+class _C {
+  int operator[](String/*!*/ s) => 1;
+}
+_f(_C c, String/*?*/ s) => c[s];
+''');
+    visitSubexpression(findNode.index('c['), 'int',
+        nullChecked: {findNode.simple('s]')});
+  }
+
+  test_indexExpression_substituted() async {
+    await analyze('''
+class _C<T, U> {
+  T operator[](U u) => throw 'foo';
+}
+_f(_C<int, String> c) => c['foo'];
+''');
+    visitSubexpression(findNode.index('c['), 'int');
+  }
+
+  test_indexExpression_substituted_check_rhs() async {
+    await analyze('''
+class _C<T, U> {
+  T operator[](U u) => throw 'foo';
+}
+_f(_C<int, String/*!*/> c, String/*?*/ s) => c[s];
+''');
+    visitSubexpression(findNode.index('c['), 'int',
+        nullChecked: {findNode.simple('s]')});
+  }
+
+  test_indexExpression_substituted_no_check_rhs() async {
+    await analyze('''
+class _C<T, U> {
+  T operator[](U u) => throw 'foo';
+}
+_f(_C<int, String/*?*/> c, String/*?*/ s) => c[s];
+''');
+    visitSubexpression(findNode.index('c['), 'int');
+  }
+
   test_integerLiteral() async {
     await analyze('''
 f() => 1;
@@ -529,6 +1045,31 @@
     visitSubexpression(findNode.integerLiteral('1'), 'int');
   }
 
+  test_listLiteral_typed() async {
+    await analyze('''
+_f() => <int>[];
+''');
+    visitSubexpression(findNode.listLiteral('['), 'List<int>');
+  }
+
+  test_listLiteral_typed_visit_contents() async {
+    await analyze('''
+_f(int/*?*/ x) => <int/*!*/>[x];
+''');
+    visitSubexpression(findNode.listLiteral('['), 'List<int>',
+        nullChecked: {findNode.simple('x]')});
+  }
+
+  test_nullAssertion_promotes() async {
+    await analyze('''
+_f(bool/*?*/ x) => x && x;
+''');
+    // Only the first `x` is null-checked because thereafter, the type of `x` is
+    // promoted to `bool`.
+    visitSubexpression(findNode.binary('&&'), 'bool',
+        nullChecked: {findNode.simple('x &&')});
+  }
+
   test_nullLiteral() async {
     await analyze('''
 f() => null;
@@ -543,6 +1084,513 @@
     visitSubexpression(findNode.integerLiteral('1'), 'int');
   }
 
+  test_parenthesizedExpression_flow() async {
+    await analyze('''
+_f(bool/*?*/ x) => ((x) != (null)) && x;
+''');
+    visitSubexpression(findNode.binary('&&'), 'bool');
+  }
+
+  test_postfixExpression_combined_nullable_noProblem() async {
+    await analyze('''
+abstract class _C {
+  _D/*?*/ operator+(int/*!*/ value);
+}
+abstract class _D extends _C {}
+abstract class _E {
+  _C/*!*/ get x;
+  void set x(_C/*?*/ value);
+  f() => x++;
+}
+''');
+    visitSubexpression(findNode.postfix('++'), '_C');
+  }
+
+  @FailingTest(issue: 'https://github.com/dart-lang/sdk/issues/38833')
+  test_postfixExpression_combined_nullable_noProblem_dynamic() async {
+    await analyze('''
+abstract class _E {
+  dynamic get x;
+  void set x(Object/*!*/ value);
+  f() => x++;
+}
+''');
+    visitSubexpression(findNode.postfix('++'), 'dynamic');
+  }
+
+  test_postfixExpression_combined_nullable_problem() async {
+    await analyze('''
+abstract class _C {
+  _D/*?*/ operator+(int/*!*/ value);
+}
+abstract class _D extends _C {}
+abstract class _E {
+  _C/*!*/ get x;
+  void set x(_C/*!*/ value);
+  f() => x++;
+}
+''');
+    var postfix = findNode.postfix('++');
+    visitSubexpression(postfix, '_C', problems: {
+      postfix: {const CompoundAssignmentCombinedNullable()}
+    });
+  }
+
+  test_postfixExpression_dynamic() async {
+    await analyze('''
+_f(dynamic x) => x++;
+''');
+    visitSubexpression(findNode.postfix('++'), 'dynamic');
+  }
+
+  test_postfixExpression_lhs_nullable_problem() async {
+    await analyze('''
+abstract class _C {
+  _D/*!*/ operator+(int/*!*/ value);
+}
+abstract class _D extends _C {}
+abstract class _E {
+  _C/*?*/ get x;
+  void set x(_C/*?*/ value);
+  f() => x++;
+}
+''');
+    var postfix = findNode.postfix('++');
+    visitSubexpression(postfix, '_C?', problems: {
+      postfix: {const CompoundAssignmentReadNullable()}
+    });
+  }
+
+  test_postfixExpression_rhs_nonNullable() async {
+    await analyze('''
+abstract class _C {
+  _D/*!*/ operator+(int/*!*/ value);
+}
+abstract class _D extends _C {}
+_f(_C/*!*/ x) => x++;
+''');
+    visitSubexpression(findNode.postfix('++'), '_C');
+  }
+
+  test_prefixedIdentifier_dynamic() async {
+    await analyze('''
+Object/*!*/ _f(dynamic d) => d.x;
+''');
+    visitSubexpression(findNode.prefixed('d.x'), 'dynamic',
+        contextType: objectType);
+  }
+
+  test_prefixedIdentifier_field_nonNullable() async {
+    await analyze('''
+class _C {
+  int/*!*/ x = 0;
+}
+_f(_C c) => c.x;
+''');
+    visitSubexpression(findNode.prefixed('c.x'), 'int');
+  }
+
+  test_prefixedIdentifier_field_nullable() async {
+    await analyze('''
+class _C {
+  int/*?*/ x = 0;
+}
+_f(_C c) => c.x;
+''');
+    visitSubexpression(findNode.prefixed('c.x'), 'int?');
+  }
+
+  test_prefixedIdentifier_getter_check_lhs() async {
+    await analyze('''
+abstract class _C {
+  int get x;
+}
+_f(_C/*?*/ c) => c.x;
+''');
+    visitSubexpression(findNode.prefixed('c.x'), 'int',
+        nullChecked: {findNode.simple('c.x')});
+  }
+
+  test_prefixedIdentifier_getter_nonNullable() async {
+    await analyze('''
+abstract class _C {
+  int/*!*/ get x;
+}
+_f(_C c) => c.x;
+''');
+    visitSubexpression(findNode.prefixed('c.x'), 'int');
+  }
+
+  test_prefixedIdentifier_getter_nullable() async {
+    await analyze('''
+abstract class _C {
+  int/*?*/ get x;
+}
+_f(_C c) => c.x;
+''');
+    visitSubexpression(findNode.prefixed('c.x'), 'int?');
+  }
+
+  test_prefixedIdentifier_object_getter() async {
+    await analyze('''
+class _C {}
+_f(_C/*?*/ c) => c.hashCode;
+''');
+    visitSubexpression(findNode.prefixed('c.hashCode'), 'int');
+  }
+
+  test_prefixedIdentifier_object_tearoff() async {
+    await analyze('''
+class _C {}
+_f(_C/*?*/ c) => c.toString;
+''');
+    visitSubexpression(findNode.prefixed('c.toString'), 'String Function()');
+  }
+
+  test_prefixedIdentifier_substituted() async {
+    await analyze('''
+abstract class _C<T> {
+  List<T> get x;
+}
+_f(_C<int> c) => c.x;
+''');
+    visitSubexpression(findNode.prefixed('c.x'), 'List<int>');
+  }
+
+  test_prefixExpression_bang_flow() async {
+    await analyze('''
+_f(int/*?*/ x) {
+  if (!(x == null)) {
+    x + 1;
+  }
+}
+''');
+    // No null check should be needed on `x + 1` because `!(x == null)` promotes
+    // x's type to `int`.
+    visitStatement(findNode.statement('if'));
+  }
+
+  test_prefixExpression_bang_nonNullable() async {
+    await analyze('''
+_f(bool/*!*/ x) => !x;
+''');
+    visitSubexpression(findNode.prefix('!x'), 'bool');
+  }
+
+  test_prefixExpression_bang_nullable() async {
+    await analyze('''
+_f(bool/*?*/ x) => !x;
+''');
+    visitSubexpression(findNode.prefix('!x'), 'bool',
+        nullChecked: {findNode.simple('x;')});
+  }
+
+  test_prefixExpression_combined_nullable_noProblem() async {
+    await analyze('''
+abstract class _C {
+  _D/*?*/ operator+(int/*!*/ value);
+}
+abstract class _D extends _C {}
+abstract class _E {
+  _C/*!*/ get x;
+  void set x(_C/*?*/ value);
+  f() => ++x;
+}
+''');
+    visitSubexpression(findNode.prefix('++'), '_D?');
+  }
+
+  test_prefixExpression_combined_nullable_noProblem_dynamic() async {
+    await analyze('''
+abstract class _E {
+  dynamic get x;
+  void set x(Object/*!*/ value);
+  f() => ++x;
+}
+''');
+    var prefix = findNode.prefix('++');
+    visitSubexpression(prefix, 'dynamic');
+  }
+
+  test_prefixExpression_combined_nullable_problem() async {
+    await analyze('''
+abstract class _C {
+  _D/*?*/ operator+(int/*!*/ value);
+}
+abstract class _D extends _C {}
+abstract class _E {
+  _C/*!*/ get x;
+  void set x(_C/*!*/ value);
+  f() => ++x;
+}
+''');
+    var prefix = findNode.prefix('++');
+    visitSubexpression(prefix, '_D', problems: {
+      prefix: {const CompoundAssignmentCombinedNullable()}
+    });
+  }
+
+  test_prefixExpression_intRules() async {
+    await analyze('''
+_f(int x) => ++x;
+''');
+    visitSubexpression(findNode.prefix('++'), 'int');
+  }
+
+  test_prefixExpression_lhs_nullable_problem() async {
+    await analyze('''
+abstract class _C {
+  _D/*!*/ operator+(int/*!*/ value);
+}
+abstract class _D extends _C {}
+abstract class _E {
+  _C/*?*/ get x;
+  void set x(_C/*?*/ value);
+  f() => ++x;
+}
+''');
+    var prefix = findNode.prefix('++');
+    visitSubexpression(prefix, '_D', problems: {
+      prefix: {const CompoundAssignmentReadNullable()}
+    });
+  }
+
+  test_prefixExpression_minus_dynamic() async {
+    await analyze('''
+_f(dynamic x) => -x;
+''');
+    visitSubexpression(findNode.prefix('-x'), 'dynamic');
+  }
+
+  test_prefixExpression_minus_nonNullable() async {
+    await analyze('''
+_f(int/*!*/ x) => -x;
+''');
+    visitSubexpression(findNode.prefix('-x'), 'int');
+  }
+
+  test_prefixExpression_minus_nullable() async {
+    await analyze('''
+_f(int/*?*/ x) => -x;
+''');
+    visitSubexpression(findNode.prefix('-x'), 'int',
+        nullChecked: {findNode.simple('x;')});
+  }
+
+  test_prefixExpression_minus_substitution() async {
+    await analyze('''
+abstract class _C<T> {
+  List<T> operator-();
+}
+_f(_C<int> x) => -x;
+''');
+    visitSubexpression(findNode.prefix('-x'), 'List<int>');
+  }
+
+  test_prefixExpression_rhs_nonNullable() async {
+    await analyze('''
+abstract class _C {
+  _D/*!*/ operator+(int/*!*/ value);
+}
+abstract class _D extends _C {}
+_f(_C/*!*/ x) => ++x;
+''');
+    visitSubexpression(findNode.prefix('++'), '_D');
+  }
+
+  test_prefixExpression_tilde_dynamic() async {
+    await analyze('''
+_f(dynamic x) => ~x;
+''');
+    visitSubexpression(findNode.prefix('~x'), 'dynamic');
+  }
+
+  test_prefixExpression_tilde_nonNullable() async {
+    await analyze('''
+_f(int/*!*/ x) => ~x;
+''');
+    visitSubexpression(findNode.prefix('~x'), 'int');
+  }
+
+  test_prefixExpression_tilde_nullable() async {
+    await analyze('''
+_f(int/*?*/ x) => ~x;
+''');
+    visitSubexpression(findNode.prefix('~x'), 'int',
+        nullChecked: {findNode.simple('x;')});
+  }
+
+  test_prefixExpression_tilde_substitution() async {
+    await analyze('''
+abstract class _C<T> {
+  List<T> operator~();
+}
+_f(_C<int> x) => ~x;
+''');
+    visitSubexpression(findNode.prefix('~x'), 'List<int>');
+  }
+
+  test_propertyAccess_dynamic() async {
+    await analyze('''
+Object/*!*/ _f(dynamic d) => (d).x;
+''');
+    visitSubexpression(findNode.propertyAccess('(d).x'), 'dynamic',
+        contextType: objectType);
+  }
+
+  test_propertyAccess_field_nonNullable() async {
+    await analyze('''
+class _C {
+  int/*!*/ x = 0;
+}
+_f(_C c) => (c).x;
+''');
+    visitSubexpression(findNode.propertyAccess('(c).x'), 'int');
+  }
+
+  test_propertyAccess_field_nullable() async {
+    await analyze('''
+class _C {
+  int/*?*/ x = 0;
+}
+_f(_C c) => (c).x;
+''');
+    visitSubexpression(findNode.propertyAccess('(c).x'), 'int?');
+  }
+
+  test_propertyAccess_getter_check_lhs() async {
+    await analyze('''
+abstract class _C {
+  int get x;
+}
+_f(_C/*?*/ c) => (c).x;
+''');
+    visitSubexpression(findNode.propertyAccess('(c).x'), 'int',
+        nullChecked: {findNode.parenthesized('(c).x')});
+  }
+
+  test_propertyAccess_getter_nonNullable() async {
+    await analyze('''
+abstract class _C {
+  int/*!*/ get x;
+}
+_f(_C c) => (c).x;
+''');
+    visitSubexpression(findNode.propertyAccess('(c).x'), 'int');
+  }
+
+  test_propertyAccess_getter_nullable() async {
+    await analyze('''
+abstract class _C {
+  int/*?*/ get x;
+}
+_f(_C c) => (c).x;
+''');
+    visitSubexpression(findNode.propertyAccess('(c).x'), 'int?');
+  }
+
+  test_propertyAccess_nullAware_dynamic() async {
+    await analyze('''
+Object/*!*/ _f(dynamic d) => d?.x;
+''');
+    visitSubexpression(findNode.propertyAccess('d?.x'), 'dynamic',
+        contextType: objectType);
+  }
+
+  test_propertyAccess_nullAware_field_nonNullable() async {
+    await analyze('''
+class _C {
+  int/*!*/ x = 0;
+}
+_f(_C/*?*/ c) => c?.x;
+''');
+    visitSubexpression(findNode.propertyAccess('c?.x'), 'int?');
+  }
+
+  test_propertyAccess_nullAware_field_nullable() async {
+    await analyze('''
+class _C {
+  int/*?*/ x = 0;
+}
+_f(_C/*?*/ c) => c?.x;
+''');
+    visitSubexpression(findNode.propertyAccess('c?.x'), 'int?');
+  }
+
+  test_propertyAccess_nullAware_getter_nonNullable() async {
+    await analyze('''
+abstract class _C {
+  int/*!*/ get x;
+}
+_f(_C/*?*/ c) => c?.x;
+''');
+    visitSubexpression(findNode.propertyAccess('c?.x'), 'int?');
+  }
+
+  test_propertyAccess_nullAware_getter_nullable() async {
+    await analyze('''
+abstract class _C {
+  int/*?*/ get x;
+}
+_f(_C/*?*/ c) => c?.x;
+''');
+    visitSubexpression(findNode.propertyAccess('c?.x'), 'int?');
+  }
+
+  test_propertyAccess_nullAware_object_getter() async {
+    await analyze('''
+class _C {}
+_f(_C/*?*/ c) => c?.hashCode;
+''');
+    visitSubexpression(findNode.propertyAccess('c?.hashCode'), 'int?');
+  }
+
+  test_propertyAccess_nullAware_object_tearoff() async {
+    await analyze('''
+class _C {}
+_f(_C/*?*/ c) => c?.toString;
+''');
+    visitSubexpression(
+        findNode.propertyAccess('c?.toString'), 'String Function()?');
+  }
+
+  test_propertyAccess_nullAware_substituted() async {
+    await analyze('''
+abstract class _C<T> {
+  List<T> get x;
+}
+_f(_C<int>/*?*/ c) => c?.x;
+''');
+    visitSubexpression(findNode.propertyAccess('c?.x'), 'List<int>?');
+  }
+
+  test_propertyAccess_object_getter() async {
+    await analyze('''
+class _C {}
+_f(_C/*?*/ c) => (c).hashCode;
+''');
+    visitSubexpression(findNode.propertyAccess('(c).hashCode'), 'int');
+  }
+
+  test_propertyAccess_object_tearoff() async {
+    await analyze('''
+class _C {}
+_f(_C/*?*/ c) => (c).toString;
+''');
+    visitSubexpression(
+        findNode.propertyAccess('(c).toString'), 'String Function()');
+  }
+
+  test_propertyAccess_substituted() async {
+    await analyze('''
+abstract class _C<T> {
+  List<T> get x;
+}
+_f(_C<int> c) => (c).x;
+''');
+    visitSubexpression(findNode.propertyAccess('(c).x'), 'List<int>');
+  }
+
   test_simpleIdentifier_className() async {
     await analyze('''
 _f() => int;
@@ -632,6 +1680,98 @@
     visitSubexpression(findNode.symbolLiteral('#foo'), 'Symbol');
   }
 
+  test_throw_flow() async {
+    await analyze('''
+_f(int/*?*/ i) {
+  if (i == null) throw 'foo';
+  i + 1;
+}
+''');
+    visitStatement(findNode.block('{'));
+  }
+
+  test_throw_nullable() async {
+    await analyze('''
+_f(int/*?*/ i) => throw i;
+''');
+    visitSubexpression(findNode.throw_('throw'), 'Never',
+        nullChecked: {findNode.simple('i;')});
+  }
+
+  test_throw_simple() async {
+    await analyze('''
+_f() => throw 'foo';
+''');
+    visitSubexpression(findNode.throw_('throw'), 'Never');
+  }
+
+  test_typeName_dynamic() async {
+    await analyze('''
+void _f() {
+  dynamic d = null;
+}
+''');
+    visitTypeAnnotation(findNode.typeAnnotation('dynamic'), 'dynamic');
+  }
+
+  test_typeName_generic_nonNullable() async {
+    await analyze('''
+void _f() {
+  List<int> i = [0];
+}
+''');
+    visitTypeAnnotation(findNode.typeAnnotation('List<int>'), 'List<int>');
+  }
+
+  test_typeName_generic_nullable() async {
+    await analyze('''
+void _f() {
+  List<int> i = null;
+}
+''');
+    var listIntAnnotation = findNode.typeAnnotation('List<int>');
+    visitTypeAnnotation(listIntAnnotation, 'List<int>?',
+        nullable: {listIntAnnotation});
+  }
+
+  test_typeName_generic_nullable_arg() async {
+    await analyze('''
+void _f() {
+  List<int> i = [null];
+}
+''');
+    visitTypeAnnotation(findNode.typeAnnotation('List<int>'), 'List<int?>',
+        nullable: {findNode.typeAnnotation('int')});
+  }
+
+  test_typeName_simple_nonNullable() async {
+    await analyze('''
+void _f() {
+  int i = 0;
+}
+''');
+    visitTypeAnnotation(findNode.typeAnnotation('int'), 'int');
+  }
+
+  test_typeName_simple_nullable() async {
+    await analyze('''
+void _f() {
+  int i = null;
+}
+''');
+    var intAnnotation = findNode.typeAnnotation('int');
+    visitTypeAnnotation((intAnnotation), 'int?', nullable: {intAnnotation});
+  }
+
+  test_typeName_void() async {
+    await analyze('''
+void _f() {
+  void v;
+}
+''');
+    visitTypeAnnotation(findNode.typeAnnotation('void v'), 'void');
+  }
+
   test_use_of_dynamic() async {
     // Use of `dynamic` in a context requiring non-null is not explicitly null
     // checked.
@@ -641,45 +1781,146 @@
     visitSubexpression(findNode.binary('&&'), 'bool');
   }
 
+  test_variableDeclaration_typed_initialized_nonNullable() async {
+    await analyze('''
+void _f() {
+  int x = 0;
+}
+''');
+    visitStatement(findNode.statement('int x'));
+  }
+
+  test_variableDeclaration_typed_initialized_nullable() async {
+    await analyze('''
+void _f() {
+  int x = null;
+}
+''');
+    visitStatement(findNode.statement('int x'),
+        nullable: {findNode.typeAnnotation('int')});
+  }
+
+  test_variableDeclaration_typed_uninitialized() async {
+    await analyze('''
+void _f() {
+  int x;
+}
+''');
+    visitStatement(findNode.statement('int x'));
+  }
+
+  test_variableDeclaration_untyped_initialized() async {
+    await analyze('''
+void _f() {
+  var x = 0;
+}
+''');
+    visitStatement(findNode.statement('var x'));
+  }
+
+  test_variableDeclaration_untyped_uninitialized() async {
+    await analyze('''
+void _f() {
+  var x;
+}
+''');
+    visitStatement(findNode.statement('var x'));
+  }
+
+  test_variableDeclaration_visit_initializer() async {
+    await analyze('''
+void _f(bool/*?*/ x, bool/*?*/ y) {
+  bool z = x && y;
+}
+''');
+    visitStatement(findNode.statement('bool z'),
+        nullChecked: {findNode.simple('x &&'), findNode.simple('y;')});
+  }
+
   void visitAssignmentTarget(
       Expression node, String expectedReadType, String expectedWriteType,
       {Set<Expression> nullChecked = const <Expression>{},
       Map<AstNode, Set<Problem>> problems = const <AstNode, Set<Problem>>{}}) {
-    var fixBuilder = _FixBuilder(
-        decoratedClassHierarchy, typeProvider, typeSystem, variables);
-    fixBuilder.createFlowAnalysis(node.thisOrAncestorOfType<FunctionBody>());
-    var targetInfo = fixBuilder.visitAssignmentTarget(node);
-    expect((targetInfo.readType as TypeImpl).toString(withNullability: true),
-        expectedReadType);
+    _FixBuilder fixBuilder = _createFixBuilder(node);
+    var targetInfo =
+        fixBuilder.visitAssignmentTarget(node, expectedReadType != null);
+    if (expectedReadType == null) {
+      expect(targetInfo.readType, null);
+    } else {
+      expect((targetInfo.readType as TypeImpl).toString(withNullability: true),
+          expectedReadType);
+    }
     expect((targetInfo.writeType as TypeImpl).toString(withNullability: true),
         expectedWriteType);
     expect(fixBuilder.nullCheckedExpressions, nullChecked);
     expect(fixBuilder.problems, problems);
   }
 
+  void visitStatement(Statement node,
+      {Set<Expression> nullChecked = const <Expression>{},
+      Map<AstNode, Set<Problem>> problems = const <AstNode, Set<Problem>>{},
+      Set<TypeAnnotation> nullable = const <TypeAnnotation>{}}) {
+    _FixBuilder fixBuilder = _createFixBuilder(node);
+    var type = node.accept(fixBuilder);
+    expect(type, null);
+    expect(fixBuilder.nullCheckedExpressions, nullChecked);
+    expect(fixBuilder.problems, problems);
+    expect(fixBuilder.nullable, nullable);
+  }
+
   void visitSubexpression(Expression node, String expectedType,
       {DartType contextType,
       Set<Expression> nullChecked = const <Expression>{},
-      Map<AstNode, Set<Problem>> problems = const <AstNode, Set<Problem>>{}}) {
+      Map<AstNode, Set<Problem>> problems = const <AstNode, Set<Problem>>{},
+      Set<TypeAnnotation> nullable = const <TypeAnnotation>{}}) {
     contextType ??= dynamicType;
-    var fixBuilder = _FixBuilder(
-        decoratedClassHierarchy, typeProvider, typeSystem, variables);
-    fixBuilder.createFlowAnalysis(node.thisOrAncestorOfType<FunctionBody>());
+    _FixBuilder fixBuilder = _createFixBuilder(node);
     var type = fixBuilder.visitSubexpression(node, contextType);
     expect((type as TypeImpl).toString(withNullability: true), expectedType);
     expect(fixBuilder.nullCheckedExpressions, nullChecked);
     expect(fixBuilder.problems, problems);
+    expect(fixBuilder.nullable, nullable);
+  }
+
+  void visitTypeAnnotation(TypeAnnotation node, String expectedType,
+      {Set<Expression> nullChecked = const <Expression>{},
+      Map<AstNode, Set<Problem>> problems = const <AstNode, Set<Problem>>{},
+      Set<TypeAnnotation> nullable = const <TypeAnnotation>{}}) {
+    _FixBuilder fixBuilder = _createFixBuilder(node);
+    var type = node.accept(fixBuilder);
+    expect((type as TypeImpl).toString(withNullability: true), expectedType);
+    expect(fixBuilder.nullCheckedExpressions, nullChecked);
+    expect(fixBuilder.problems, problems);
+    expect(fixBuilder.nullable, nullable);
+  }
+
+  _FixBuilder _createFixBuilder(AstNode node) {
+    var fixBuilder = _FixBuilder(testSource, decoratedClassHierarchy,
+        typeProvider, typeSystem, variables);
+    var body = node.thisOrAncestorOfType<FunctionBody>();
+    var declaration = body.thisOrAncestorOfType<Declaration>();
+    fixBuilder.createFlowAnalysis(declaration, null);
+    return fixBuilder;
   }
 }
 
 class _FixBuilder extends FixBuilder {
   final Set<Expression> nullCheckedExpressions = {};
 
+  final Set<TypeAnnotation> nullable = {};
+
   final Map<AstNode, Set<Problem>> problems = {};
 
-  _FixBuilder(DecoratedClassHierarchy decoratedClassHierarchy,
+  _FixBuilder(Source source, DecoratedClassHierarchy decoratedClassHierarchy,
       TypeProvider typeProvider, TypeSystem typeSystem, Variables variables)
-      : super(decoratedClassHierarchy, typeProvider, typeSystem, variables);
+      : super(source, decoratedClassHierarchy, typeProvider, typeSystem,
+            variables);
+
+  @override
+  void addNullable(TypeAnnotation node) {
+    var newlyAdded = nullable.add(node);
+    expect(newlyAdded, true);
+  }
 
   @override
   void addNullCheck(Expression subexpression) {
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 687c3b0..5b741e2 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -120,6 +120,7 @@
 [ $runtime != vm ]
 dev_compiler/test/options/*: SkipByDesign
 front_end/test/hot_reload_e2e_test: Skip
+frontend_server/test/*: SkipByDesign # Only meant to run on vm
 vm/test/*: SkipByDesign # Only meant to run on vm
 vm_service/test/*: SkipByDesign # Uses dart:io
 
diff --git a/pkg/smith/lib/configuration.dart b/pkg/smith/lib/configuration.dart
index 74ff985..ac3df99 100644
--- a/pkg/smith/lib/configuration.dart
+++ b/pkg/smith/lib/configuration.dart
@@ -246,7 +246,7 @@
         builderTag: stringOption("builder-tag"),
         vmOptions: stringListOption("vm-options"),
         dart2jsOptions: stringListOption("dart2js-options"),
-        experiments: stringListOption("experiments"),
+        experiments: stringListOption("enable-experiment"),
         timeout: intOption("timeout"),
         enableAsserts: boolOption("enable-asserts"),
         isChecked: boolOption("checked"),
@@ -471,7 +471,7 @@
     if (builderTag.isNotEmpty) fields.add("builder-tag: $builderTag");
     stringListField("vm-options", vmOptions);
     stringListField("dart2js-options", dart2jsOptions);
-    stringListField("experiments", experiments);
+    stringListField("enable-experiment", experiments);
     if (timeout > 0) fields.add("timeout: $timeout");
     if (enableAsserts) fields.add("enable-asserts");
     if (isChecked) fields.add("checked");
diff --git a/pkg/smith/test/configuration_test.dart b/pkg/smith/test/configuration_test.dart
index 4f5736e..e391225 100644
--- a/pkg/smith/test/configuration_test.dart
+++ b/pkg/smith/test/configuration_test.dart
@@ -202,7 +202,7 @@
               "builder-tag": "the tag",
               "vm-options": ["vm stuff", "more vm stuff"],
               "dart2js-options": ["dart2js stuff", "more dart2js stuff"],
-              "experiments": ["semicolons", "interrobangs"],
+              "enable-experiment": ["semicolons", "interrobangs"],
               "enable-asserts": true,
               "checked": true,
               "csp": true,
diff --git a/pkg/test_runner/lib/src/command.dart b/pkg/test_runner/lib/src/command.dart
index 6732b5b..bcf4024 100644
--- a/pkg/test_runner/lib/src/command.dart
+++ b/pkg/test_runner/lib/src/command.dart
@@ -14,11 +14,6 @@
 
 /// A command executed as a step in a test case.
 abstract class Command {
-  static Command browserTest(String url, TestConfiguration configuration,
-      {bool retry}) {
-    return BrowserTestCommand._(url, configuration, retry);
-  }
-
   /// A descriptive name for this command.
   final String displayName;
 
@@ -395,12 +390,11 @@
   final TestConfiguration configuration;
   final bool retry;
 
-  BrowserTestCommand._(this.url, this.configuration, this.retry,
-      {int index = 0})
+  BrowserTestCommand(this.url, this.configuration, {this.retry, int index = 0})
       : super._(configuration.runtime.name, index: index);
 
   BrowserTestCommand indexedCopy(int index) =>
-      BrowserTestCommand._(url, configuration, retry, index: index);
+      BrowserTestCommand(url, configuration, retry: retry, index: index);
 
   void _buildHashCode(HashCodeBuilder builder) {
     super._buildHashCode(builder);
diff --git a/pkg/test_runner/lib/src/command_output.dart b/pkg/test_runner/lib/src/command_output.dart
index 98f5983..9898e75 100644
--- a/pkg/test_runner/lib/src/command_output.dart
+++ b/pkg/test_runner/lib/src/command_output.dart
@@ -23,7 +23,7 @@
 /// and the time the process took to run. It does not contain a pointer to the
 /// [TestCase] this is the output of, so some functions require the test case
 /// to be passed as an argument.
-class CommandOutput extends UniqueObject {
+class CommandOutput {
   final Command command;
 
   final bool hasTimedOut;
diff --git a/pkg/test_runner/lib/src/compiler_configuration.dart b/pkg/test_runner/lib/src/compiler_configuration.dart
index fd5142e..0874125 100644
--- a/pkg/test_runner/lib/src/compiler_configuration.dart
+++ b/pkg/test_runner/lib/src/compiler_configuration.dart
@@ -18,6 +18,21 @@
       .toList();
 }
 
+/// Generates a list with a single `--enable-experiment=` option that includes
+/// all experiments enabled by [configuration] and [testFile].
+///
+/// Returns an empty list if there are no experiments to enable. Returning a
+/// list allows the result of calling this to be spread into another list.
+List<String> _experimentsArgument(
+    TestConfiguration configuration, TestFile testFile) {
+  if (configuration.experiments.isEmpty && testFile.experiments.isEmpty) {
+    return const [];
+  }
+
+  var experiments = [...configuration.experiments, ...testFile.experiments];
+  return ["--enable-experiment=${experiments.join(',')}"];
+}
+
 /// Grouping of a command with its expected result.
 class CommandArtifact {
   final List<Command> commands;
@@ -128,6 +143,7 @@
     return [
       ...testFile.sharedOptions,
       ..._configuration.sharedOptions,
+      ..._experimentsArgument(_configuration, testFile),
       ...args
     ];
   }
@@ -164,6 +180,7 @@
       ...vmOptions,
       ...testFile.sharedOptions,
       ..._configuration.sharedOptions,
+      ..._experimentsArgument(_configuration, testFile),
       ...originalArguments,
       ...testFile.dartOptions
     ];
@@ -205,6 +222,7 @@
     return [
       ...testFile.sharedOptions,
       ..._configuration.sharedOptions,
+      ..._experimentsArgument(_configuration, testFile),
       ...vmOptions,
       ...args
     ];
@@ -232,6 +250,7 @@
       ...vmOptions,
       ...testFile.sharedOptions,
       ..._configuration.sharedOptions,
+      ..._experimentsArgument(_configuration, testFile),
       ..._replaceDartFiles(originalArguments, filename),
       ...testFile.dartOptions
     ];
@@ -324,6 +343,7 @@
       ...vmOptions,
       ...testFile.sharedOptions,
       ..._configuration.sharedOptions,
+      ..._experimentsArgument(_configuration, testFile),
       ...args
     ];
   }
@@ -406,6 +426,7 @@
     return [
       ...testFile.sharedOptions,
       ..._configuration.sharedOptions,
+      ..._experimentsArgument(_configuration, testFile),
       ...testFile.dart2jsOptions,
       ...args
     ];
@@ -482,6 +503,7 @@
     return [
       ...testFile.sharedOptions,
       ..._configuration.sharedOptions,
+      ..._experimentsArgument(_configuration, testFile),
       ...testFile.ddcOptions,
       // The file being compiled is the last argument.
       args.last
@@ -816,6 +838,7 @@
       ...filterVmOptions(vmOptions),
       ...testFile.sharedOptions,
       ..._configuration.sharedOptions,
+      ..._experimentsArgument(_configuration, testFile),
       ...args
     ];
   }
@@ -840,6 +863,7 @@
       ...vmOptions,
       ...testFile.sharedOptions,
       ..._configuration.sharedOptions,
+      ..._experimentsArgument(_configuration, testFile),
       ...originalArguments,
       ...testFile.dartOptions
     ];
@@ -886,6 +910,7 @@
       ...vmOptions,
       ...testFile.sharedOptions,
       ..._configuration.sharedOptions,
+      ..._experimentsArgument(_configuration, testFile),
       ...args,
       ...testFile.dartOptions
     ];
@@ -902,6 +927,7 @@
       ...vmOptions,
       ...testFile.sharedOptions,
       ..._configuration.sharedOptions,
+      ..._experimentsArgument(_configuration, testFile),
       ..._replaceDartFiles(originalArguments, artifact.filename),
       ...testFile.dartOptions
     ];
@@ -1158,7 +1184,8 @@
       TestFile testFile, List<String> vmOptions, List<String> args) {
     var arguments = [
       ...testFile.sharedOptions,
-      ..._configuration.sharedOptions
+      ..._configuration.sharedOptions,
+      ..._experimentsArgument(_configuration, testFile)
     ];
     for (var argument in args) {
       if (argument == "--ignore-unrecognized-flags") continue;
diff --git a/pkg/test_runner/lib/src/configuration.dart b/pkg/test_runner/lib/src/configuration.dart
index 3f170e2..d91dc66 100644
--- a/pkg/test_runner/lib/src/configuration.dart
+++ b/pkg/test_runner/lib/src/configuration.dart
@@ -208,7 +208,7 @@
 
   /// The base directory named for this configuration, like:
   ///
-  ///     none_vm_release_x64
+  ///     ReleaseX64
   String _configurationDirectory;
 
   String get configurationDirectory {
@@ -218,7 +218,7 @@
 
   /// The build directory path for this configuration, like:
   ///
-  ///     build/none_vm_release_x64
+  ///     build/ReleaseX64
   String get buildDirectory => system.outputDirectory + configurationDirectory;
 
   int _timeout;
@@ -456,15 +456,24 @@
   /// build_directory).
   String _calculateDirectory() {
     // Capitalize the mode name.
-    var modeName =
+    var result =
         mode.name.substring(0, 1).toUpperCase() + mode.name.substring(1);
 
-    var os = '';
-    if (system == System.android) os = "Android";
+    if (system == System.android) result += "Android";
 
     var arch = architecture.name.toUpperCase();
-    var normal = '$modeName$os$arch';
-    var cross = '$modeName${os}X$arch';
+    var normal = '$result$arch';
+    var cross = '${result}X$arch';
+
+    // TODO(38701): When enabling the NNBD experiment, we need to use the
+    // forked version of the SDK core libraries that have NNBD support. Remove
+    // this once the forked SDK at `<repo>/sdk_nnbd` has been merged back with
+    // `<repo>/sdk`.
+    if (experiments.contains("non-nullable")) {
+      normal += "NNBD";
+      cross += "NNBD";
+    }
+
     var outDir = system.outputDirectory;
     var normalDir = Directory(Path('$outDir$normal').toNativePath());
     var crossDir = Directory(Path('$outDir$cross').toNativePath());
@@ -474,9 +483,7 @@
           " binary to use.";
     }
 
-    if (crossDir.existsSync()) return cross;
-
-    return normal;
+    return crossDir.existsSync() ? cross : normal;
   }
 }
 
diff --git a/pkg/test_runner/lib/src/dependency_graph.dart b/pkg/test_runner/lib/src/dependency_graph.dart
index bf89d9e..77341ab 100644
--- a/pkg/test_runner/lib/src/dependency_graph.dart
+++ b/pkg/test_runner/lib/src/dependency_graph.dart
@@ -4,8 +4,6 @@
 
 import 'dart:async';
 
-import 'utils.dart';
-
 /// A directed acyclic graph where each node is in a [NodeState] and can have
 /// data attached to it with [Node.data].
 ///
@@ -112,7 +110,7 @@
 }
 
 /// A single node in a [Graph].
-class Node<T> extends UniqueObject {
+class Node<T> {
   final T data;
   final bool timingDependency;
   NodeState _state = NodeState.initialized;
diff --git a/pkg/test_runner/lib/src/options.dart b/pkg/test_runner/lib/src/options.dart
index 9815950..029dfe9 100644
--- a/pkg/test_runner/lib/src/options.dart
+++ b/pkg/test_runner/lib/src/options.dart
@@ -311,7 +311,7 @@
     _Option('dart2js_options', 'Extra options for dart2js compilation step.',
         hide: true),
     _Option('shared_options', 'Extra shared options.', hide: true),
-    _Option('experiments', 'Experiment flags to enable.'),
+    _Option('enable-experiment', 'Experiment flags to enable.'),
     _Option(
         'babel',
         '''Transforms dart2js output with Babel. The value must be
@@ -637,7 +637,7 @@
     var dart2jsOptions = listOption("dart2js_options");
     var vmOptions = listOption("vm_options");
     var sharedOptions = listOption("shared_options");
-    var experiments = listOption("experiments");
+    var experiments = listOption("enable-experiment");
 
     // JSON reporting implies listing and reporting.
     if (data['report_in_json'] as bool) {
diff --git a/pkg/test_runner/lib/src/static_error.dart b/pkg/test_runner/lib/src/static_error.dart
index e339a5e..8d06966 100644
--- a/pkg/test_runner/lib/src/static_error.dart
+++ b/pkg/test_runner/lib/src/static_error.dart
@@ -83,7 +83,7 @@
   /// Determines whether all [actualErrors] match the given [expectedErrors].
   ///
   /// If they match, returns `null`. Otherwise returns a string describing the
-  /// mismatches. This for a human-friendly explanation of the difference
+  /// mismatches. This is a human-friendly explanation of the difference
   /// between the two sets of errors, while also being simple to implement.
   /// An expected error that is completely identical to an actual error is
   /// treated as a match. Everything else is a failure.
@@ -130,14 +130,20 @@
             actualIndex < sortedActual.length;) {
       var expected = sortedExpected[expectedIndex];
       var actual = sortedActual[actualIndex];
+
       var differences = expected.describeDifferences(actual);
       if (differences == null) {
-        expectedIndex++;
+        // Consume this actual error.
         actualIndex++;
-        continue;
-      }
 
-      if (expected.line == actual.line) {
+        // Consume the expectation, unless it's an unspecified error that can
+        // match more actual errors.
+        if (expected.isSpecifiedFor(actual) ||
+            actualIndex == sortedActual.length ||
+            sortedActual[actualIndex].line != expected.line) {
+          expectedIndex++;
+        }
+      } else if (expected.line == actual.line) {
         buffer.writeln("Wrong static error at ${expected.location}:");
         for (var difference in differences) {
           buffer.writeln("- $difference");
@@ -264,6 +270,13 @@
     return thisMessage.compareTo(otherMessage);
   }
 
+  /// Whether this error expectation is a specified error for the front end
+  /// reported by [actual].
+  bool isSpecifiedFor(StaticError actual) {
+    if (actual.isAnalyzer) return isAnalyzer && code != _unspecified;
+    return isCfe && message != _unspecified;
+  }
+
   /// Compares this error expectation to [actual].
   ///
   /// If this error correctly matches [actual], returns `null`. Otherwise
@@ -285,9 +298,7 @@
 
     // If the error is unspecified on the front end being tested, the column
     // and length can be any values.
-    var requirePreciseLocation = code != _unspecified && actual.isAnalyzer ||
-        message != _unspecified && actual.isCfe;
-    if (requirePreciseLocation) {
+    if (isSpecifiedFor(actual)) {
       if (column != actual.column) {
         differences
             .add("Expected on column $column but was on ${actual.column}.");
diff --git a/pkg/test_runner/lib/src/test_case.dart b/pkg/test_runner/lib/src/test_case.dart
index 0dfc63f..b317545 100644
--- a/pkg/test_runner/lib/src/test_case.dart
+++ b/pkg/test_runner/lib/src/test_case.dart
@@ -44,7 +44,7 @@
 /// for evaluating if the test has passed, failed, crashed, or timed out, and
 /// the TestCase has information about what the expected result of the test
 /// should be.
-class TestCase extends UniqueObject {
+class TestCase {
   /// A list of commands to execute. Most test cases have a single command.
   /// Dart2js tests have two commands, one to compile the source and another
   /// to execute it. Some isolate tests might even have three, if they require
diff --git a/pkg/test_runner/lib/src/test_file.dart b/pkg/test_runner/lib/src/test_file.dart
index f908add..11c1d4bf 100644
--- a/pkg/test_runner/lib/src/test_file.dart
+++ b/pkg/test_runner/lib/src/test_file.dart
@@ -20,6 +20,7 @@
 final _environmentRegExp = RegExp(r"// Environment=(.*)");
 final _packageRootRegExp = RegExp(r"// PackageRoot=(.*)");
 final _packagesRegExp = RegExp(r"// Packages=(.*)");
+final _experimentRegExp = RegExp(r"^--enable-experiment=([a-z,-]+)$");
 
 List<String> _splitWords(String s) =>
     s.split(' ').where((e) => e != '').toList();
@@ -128,7 +129,7 @@
 ///
 ///         // VMOptions=--flag1 --flag2
 ///
-/// *   Flags can be passed to dart2js, vm or dartdevc by adding a comment to
+/// *   Flags can be passed to dart2js, VM or dartdevc by adding a comment to
 ///     the test file:
 ///
 ///         // SharedOptions=--flag1 --flag2
@@ -223,6 +224,28 @@
     var sharedObjects = _parseStringOption(filePath, contents, 'SharedObjects',
         allowMultiple: true);
 
+    // Extract the experiments from the shared options.
+    // TODO(rnystrom): Either tests should stop specifying experiment flags
+    // entirely and use "// Requirements=", or we should come up with a better
+    // syntax. Parsing from "// SharedOptions=" for now since that's where they
+    // are currently specified.
+    var experiments = <String>[];
+    for (var i = 0; i < sharedOptions.length; i++) {
+      var sharedOption = sharedOptions[i];
+      if (sharedOption.contains("--enable-experiment")) {
+        var match = _experimentRegExp.firstMatch(sharedOption);
+        if (match == null) {
+          throw Exception(
+              "SharedOptions marker cannot mix experiment flags with other "
+              "flags. Was:\n$sharedOption");
+        }
+
+        experiments.addAll(match.group(1).split(","));
+        sharedOptions.removeAt(i);
+        i--;
+      }
+    }
+
     // Environment.
     Map<String, String> environment;
     matches = _environmentRegExp.allMatches(contents);
@@ -333,7 +356,8 @@
         ddcOptions: ddcOptions,
         vmOptions: vmOptions,
         sharedObjects: sharedObjects,
-        otherResources: otherResources);
+        otherResources: otherResources,
+        experiments: experiments);
   }
 
   /// A special fake test file for representing a VM unit test written in C++.
@@ -357,6 +381,7 @@
         vmOptions = [],
         sharedObjects = [],
         otherResources = [],
+        experiments = [],
         super(null, null, []);
 
   TestFile._(Path suiteDirectory, Path path, List<StaticError> expectedErrors,
@@ -378,7 +403,8 @@
       this.ddcOptions,
       this.vmOptions,
       this.sharedObjects,
-      this.otherResources})
+      this.otherResources,
+      this.experiments})
       : super(suiteDirectory, path, expectedErrors) {
     assert(!isMultitest || dartOptions.isEmpty);
   }
@@ -417,6 +443,13 @@
   final List<String> sharedObjects;
   final List<String> otherResources;
 
+  /// The experiments this test enables.
+  ///
+  /// Parsed from a shared options line like:
+  ///
+  ///     // SharedOptions=--enable-experiment=flubber,gloop
+  final List<String> experiments;
+
   /// Derive a multitest test section file from this multitest file with the
   /// given [multitestKey] and expectations.
   TestFile split(Path path, String multitestKey, String contents,
@@ -451,6 +484,7 @@
   vmOptions: $vmOptions
   sharedObjects: $sharedObjects
   otherResources: $otherResources
+  experiments: $experiments
 )""";
 }
 
@@ -494,6 +528,7 @@
 
   List<String> get otherResources => _origin.otherResources;
   List<String> get sharedObjects => _origin.sharedObjects;
+  List<String> get experiments => _origin.experiments;
   List<String> get sharedOptions => _origin.sharedOptions;
   List<String> get subtestNames => _origin.subtestNames;
   List<List<String>> get vmOptions => _origin.vmOptions;
diff --git a/pkg/test_runner/lib/src/test_suite.dart b/pkg/test_runner/lib/src/test_suite.dart
index 08fc09b..31b7f32 100644
--- a/pkg/test_runner/lib/src/test_suite.dart
+++ b/pkg/test_runner/lib/src/test_suite.dart
@@ -14,6 +14,7 @@
 import 'dart:math';
 
 import "package:status_file/expectation.dart";
+import 'package:test_runner/src/feature.dart';
 
 import 'browser.dart';
 import 'command.dart';
@@ -135,6 +136,24 @@
   /// fundamental reasons.
   bool _isRelevantTest(
       TestFile testFile, String displayName, Set<Expectation> expectations) {
+    // TODO(38390): Temporary hack. Right now, when analyzer is run with the
+    // NNBD experiment enabled, it implicitly opts the code into NNBD as well.
+    // (In other words, it defaults to "weak" instead of "legacy"). We want to
+    // create a test configuration that enables the NNBD experiment for the
+    // tests in language_2/nnbd/ that *do* require NNBD. That configuration will
+    // fail many of the older language tests if analyzer treats them as being
+    // opted in to NNBD instead of as legacy mode.
+    //
+    // 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") &&
+        !(testFile.requirements.contains(Feature.nnbd) ||
+            testFile.requirements.contains(Feature.nnbdWeak) ||
+            testFile.requirements.contains(Feature.nnbdStrong))) {
+      return false;
+    }
+
     // Test if the selector includes this test.
     var pattern = configuration.selectors[suiteName];
     if (!pattern.hasMatch(displayName)) {
@@ -860,7 +879,7 @@
     var htmlPathSubtest = _createUrlPathFromFile(Path(htmlPath));
     var fullHtmlPath = _uriForBrowserTest(htmlPathSubtest, subtestName);
 
-    commands.add(Command.browserTest(fullHtmlPath, configuration,
+    commands.add(BrowserTestCommand(fullHtmlPath, configuration,
         retry: !isNegative(testFile)));
 
     var fullName = testName;
@@ -951,7 +970,7 @@
       super._enqueueBrowserTest(testFile, expectations, onTest);
     } else {
       var fullPath = _createUrlPathFromFile(customHtmlPath);
-      var command = Command.browserTest(fullPath, configuration,
+      var command = BrowserTestCommand(fullPath, configuration,
           retry: !isNegative(testFile));
       _addTestCase(testFile, testFile.name, [command],
           expectations[testFile.name], onTest);
diff --git a/pkg/test_runner/lib/src/utils.dart b/pkg/test_runner/lib/src/utils.dart
index 197d995..e62242e 100644
--- a/pkg/test_runner/lib/src/utils.dart
+++ b/pkg/test_runner/lib/src/utils.dart
@@ -299,17 +299,6 @@
   }
 }
 
-class UniqueObject {
-  static int _nextId = 1;
-  final int _hashCode;
-
-  int get hashCode => _hashCode;
-  operator ==(Object other) =>
-      other is UniqueObject && _hashCode == other._hashCode;
-
-  UniqueObject() : _hashCode = ++_nextId;
-}
-
 class LastModifiedCache {
   final Map<String, DateTime> _cache = {};
 
diff --git a/pkg/test_runner/test/static_error_test.dart b/pkg/test_runner/test/static_error_test.dart
index 806e077..000830b 100644
--- a/pkg/test_runner/test/static_error_test.dart
+++ b/pkg/test_runner/test/static_error_test.dart
@@ -8,6 +8,7 @@
 
 void main() {
   testFlags();
+  testIsSpecifiedFor();
   testCompareTo();
   testDescribeDifferences();
   testSimplify();
@@ -50,6 +51,59 @@
   Expect.isTrue(both.isCfe);
 }
 
+void testIsSpecifiedFor() {
+  var specifiedBoth = StaticError(
+      line: 1, column: 2, length: 3, code: "ERR.CODE", message: "Message.");
+  var unspecifiedBoth = StaticError(
+      line: 1,
+      column: 2,
+      length: 3,
+      code: "unspecified",
+      message: "unspecified");
+  var specifiedAnalyzer = StaticError(
+      line: 1, column: 2, length: 3, code: "ERR.CODE", message: "unspecified");
+  var specifiedCfe = StaticError(
+      line: 1, column: 2, length: 3, code: "unspecified", message: "Message.");
+
+  var specifiedAnalyzerOnly =
+      StaticError(line: 1, column: 2, length: 3, code: "ERR.CODE");
+  var specifiedCfeOnly =
+      StaticError(line: 1, column: 2, length: 3, message: "Message.");
+
+  var unspecifiedAnalyzerOnly =
+      StaticError(line: 1, column: 2, length: 3, code: "unspecified");
+  var unspecifiedCfeOnly =
+      StaticError(line: 1, column: 2, length: 3, message: "unspecified");
+
+  var analyzer = StaticError(line: 1, column: 2, length: 3, code: "E.CODE");
+  var cfe = StaticError(line: 1, column: 2, length: 3, message: "E.");
+
+  // isSpecifiedFor().
+  Expect.isTrue(specifiedBoth.isSpecifiedFor(analyzer));
+  Expect.isTrue(specifiedBoth.isSpecifiedFor(cfe));
+
+  Expect.isFalse(unspecifiedBoth.isSpecifiedFor(analyzer));
+  Expect.isFalse(unspecifiedBoth.isSpecifiedFor(cfe));
+
+  Expect.isTrue(specifiedAnalyzer.isSpecifiedFor(analyzer));
+  Expect.isFalse(specifiedAnalyzer.isSpecifiedFor(cfe));
+
+  Expect.isFalse(specifiedCfe.isSpecifiedFor(analyzer));
+  Expect.isTrue(specifiedCfe.isSpecifiedFor(cfe));
+
+  Expect.isTrue(specifiedAnalyzerOnly.isSpecifiedFor(analyzer));
+  Expect.isFalse(specifiedAnalyzerOnly.isSpecifiedFor(cfe));
+
+  Expect.isFalse(specifiedCfeOnly.isSpecifiedFor(analyzer));
+  Expect.isTrue(specifiedCfeOnly.isSpecifiedFor(cfe));
+
+  Expect.isFalse(unspecifiedAnalyzerOnly.isSpecifiedFor(analyzer));
+  Expect.isFalse(unspecifiedAnalyzerOnly.isSpecifiedFor(cfe));
+
+  Expect.isFalse(unspecifiedCfeOnly.isSpecifiedFor(analyzer));
+  Expect.isFalse(unspecifiedCfeOnly.isSpecifiedFor(cfe));
+}
+
 void testCompareTo() {
   var errors = [
     // Order by line.
@@ -555,6 +609,122 @@
 
 Unexpected static error at line 7, column 9, length 3:
 - Had error code ACT.UAL.""");
+
+  // Unspecified errors can match multiple errors on the same line.
+
+  // Unspecified CFE-only error.
+  expectValidate([
+    StaticError(line: 2, column: 2, length: 3, message: "unspecified"),
+  ], [
+    StaticError(line: 2, column: 1, length: 3, message: "Actual 1."),
+    StaticError(line: 2, column: 2, length: 3, message: "Actual 2."),
+    StaticError(line: 2, column: 3, length: 3, message: "Actual 3."),
+  ], null);
+
+  // Unspecified on both.
+  expectValidate([
+    StaticError(
+        line: 2,
+        column: 2,
+        length: 3,
+        code: "unspecified",
+        message: "unspecified"),
+  ], [
+    StaticError(line: 2, column: 1, length: 3, message: "Actual 1."),
+    StaticError(line: 2, column: 2, length: 3, message: "Actual 2."),
+    StaticError(line: 2, column: 3, length: 3, message: "Actual 3."),
+  ], null);
+
+  // Unspecified on CFE, specified on analyzer.
+  expectValidate([
+    StaticError(
+        line: 2,
+        column: 2,
+        length: 3,
+        code: "ERR.CODE",
+        message: "unspecified"),
+  ], [
+    StaticError(line: 2, column: 1, length: 3, message: "Actual 1."),
+    StaticError(line: 2, column: 2, length: 3, message: "Actual 2."),
+    StaticError(line: 2, column: 3, length: 3, message: "Actual 3."),
+  ], null);
+
+  // Specified on CFE, unspecified on analyzer.
+  expectValidate([
+    StaticError(
+        line: 2,
+        column: 1,
+        length: 3,
+        code: "unspecified",
+        message: "Actual 1."),
+  ], [
+    // These are not matched.
+    StaticError(line: 2, column: 1, length: 3, message: "Actual 1."),
+    StaticError(line: 2, column: 2, length: 3, message: "Actual 2."),
+    StaticError(line: 2, column: 3, length: 3, message: "Actual 3."),
+  ], """
+Unexpected static error at line 2, column 2, length 3:
+- Had error message 'Actual 2.'.
+
+Unexpected static error at line 2, column 3, length 3:
+- Had error message 'Actual 3.'.""");
+
+  // Unspecified analyzer-only error.
+  expectValidate([
+    StaticError(line: 2, column: 1, length: 3, code: "unspecified"),
+  ], [
+    StaticError(line: 2, column: 1, length: 3, code: "ERR.CODE1"),
+    StaticError(line: 2, column: 2, length: 3, code: "ERR.CODE2"),
+    StaticError(line: 2, column: 3, length: 3, code: "ERR.CODE3"),
+  ], null);
+
+  // Unspecified on both.
+  expectValidate([
+    StaticError(
+        line: 2,
+        column: 1,
+        length: 3,
+        code: "unspecified",
+        message: "unspecified"),
+  ], [
+    StaticError(line: 2, column: 1, length: 3, code: "ERR.CODE1"),
+    StaticError(line: 2, column: 2, length: 3, code: "ERR.CODE2"),
+    StaticError(line: 2, column: 3, length: 3, code: "ERR.CODE3"),
+  ], null);
+
+  // Unspecified on analyzer, specified on CFE.
+  expectValidate([
+    StaticError(
+        line: 2,
+        column: 1,
+        length: 3,
+        code: "unspecified",
+        message: "Message."),
+  ], [
+    StaticError(line: 2, column: 1, length: 3, code: "ERR.CODE1"),
+    StaticError(line: 2, column: 2, length: 3, code: "ERR.CODE2"),
+    StaticError(line: 2, column: 3, length: 3, code: "ERR.CODE3"),
+  ], null);
+
+  // Specified on analyzer, unspecified on CFE.
+  expectValidate([
+    StaticError(
+        line: 2,
+        column: 1,
+        length: 3,
+        code: "ERR.CODE1",
+        message: "unspecified"),
+  ], [
+    // These are not matched.
+    StaticError(line: 2, column: 1, length: 3, code: "ERR.CODE1"),
+    StaticError(line: 2, column: 2, length: 3, code: "ERR.CODE2"),
+    StaticError(line: 2, column: 3, length: 3, code: "ERR.CODE3"),
+  ], """
+Unexpected static error at line 2, column 2, length 3:
+- Had error code ERR.CODE2.
+
+Unexpected static error at line 2, column 3, length 3:
+- Had error code ERR.CODE3.""");
 }
 
 void expectNoDifferences(StaticError expectedError, StaticError actualError) {
diff --git a/pkg/test_runner/test/test_file_test.dart b/pkg/test_runner/test/test_file_test.dart
index 7418bda..6bbf66e 100644
--- a/pkg/test_runner/test/test_file_test.dart
+++ b/pkg/test_runner/test/test_file_test.dart
@@ -24,6 +24,7 @@
   testParseOtherOptions();
   testParseEnvironment();
   testParsePackages();
+  testParseExperiments();
   testParseMultitest();
   testParseMultiHtmltest();
   testParseErrorFlags();
@@ -201,6 +202,38 @@
   """);
 }
 
+void testParseExperiments() {
+  // No option.
+  var file = parseTestFile("");
+  Expect.isTrue(file.experiments.isEmpty);
+
+  // Single non-experiment option.
+  file = parseTestFile("""
+  /\/ SharedOptions=not-experiment
+  """);
+  Expect.isTrue(file.experiments.isEmpty);
+  Expect.listEquals(["not-experiment"], file.sharedOptions);
+
+  // Experiments.
+  file = parseTestFile("""
+  /\/ SharedOptions=--enable-experiment=flubber,gloop
+  """);
+  Expect.listEquals(["flubber", "gloop"], file.experiments);
+  Expect.isTrue(file.sharedOptions.isEmpty);
+
+  // Experiment option mixed with other options.
+  file = parseTestFile("""
+  /\/ SharedOptions=-a --enable-experiment=flubber --other
+  """);
+  Expect.listEquals(["flubber"], file.experiments);
+  Expect.listEquals(["-a", "--other"], file.sharedOptions);
+
+  // Poorly-formatted experiment option.
+  expectParseThrows("""
+  /\/ SharedOptions=stuff--enable-experiment=flubber,gloop
+  """);
+}
+
 void testParseMultitest() {
   // Not present.
   var file = parseTestFile("");
diff --git a/pkg/test_runner/tool/update_static_error_tests.dart b/pkg/test_runner/tool/update_static_error_tests.dart
index 9fa7acb..d763c9f 100644
--- a/pkg/test_runner/tool/update_static_error_tests.dart
+++ b/pkg/test_runner/tool/update_static_error_tests.dart
@@ -144,17 +144,22 @@
   var source = file.readAsStringSync();
   var testFile = TestFile.parse(Path("."), file.path, source);
 
+  var options = testFile.sharedOptions.toList();
+  if (testFile.experiments.isNotEmpty) {
+    options.add("--enable-experiment=${testFile.experiments.join(',')}");
+  }
+
   var errors = <StaticError>[];
   if (insertAnalyzer) {
     stdout.write("\r${file.path} (Running analyzer...)");
-    errors.addAll(await _runAnalyzer(file.path, testFile.sharedOptions));
+    errors.addAll(await _runAnalyzer(file.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, testFile.sharedOptions));
+    errors.addAll(await _runCfe(file.path, options));
   }
 
   errors = StaticError.simplify(errors);
diff --git a/pkg/vm/bin/kernel_service.dart b/pkg/vm/bin/kernel_service.dart
index 39781dc..00753c0 100644
--- a/pkg/vm/bin/kernel_service.dart
+++ b/pkg/vm/bin/kernel_service.dart
@@ -147,7 +147,6 @@
           case Severity.warning:
             printMessage = !suppressWarnings;
             break;
-          case Severity.errorLegacyWarning:
           case Severity.context:
           case Severity.ignored:
             throw "Unexpected severity: ${message.severity}";
diff --git a/pkg/vm/lib/bytecode/constant_pool.dart b/pkg/vm/lib/bytecode/constant_pool.dart
index 481e0c2..4dd58a2 100644
--- a/pkg/vm/lib/bytecode/constant_pool.dart
+++ b/pkg/vm/lib/bytecode/constant_pool.dart
@@ -734,6 +734,9 @@
 
   int addString(String value) => addObjectRef(new StringConstant(value));
 
+  int addName(String name) =>
+      _add(new ConstantObjectRef(objectTable.getPublicNameHandle(name)));
+
   int addArgDesc(int numArguments,
           {int numTypeArgs = 0, List<String> argNames = const <String>[]}) =>
       _add(new ConstantObjectRef(
diff --git a/pkg/vm/lib/bytecode/dbc.dart b/pkg/vm/lib/bytecode/dbc.dart
index f14f6fec..b17b227 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 = 22;
+const int currentBytecodeFormatVersion = 23;
 
 enum Opcode {
   kUnusedOpcode000,
diff --git a/pkg/vm/lib/bytecode/declarations.dart b/pkg/vm/lib/bytecode/declarations.dart
index f4c4fc5..c4c34b1 100644
--- a/pkg/vm/lib/bytecode/declarations.dart
+++ b/pkg/vm/lib/bytecode/declarations.dart
@@ -19,6 +19,7 @@
   static const usesDartMirrorsFlag = 1 << 0;
   static const usesDartFfiFlag = 1 << 1;
   static const hasExtensionsFlag = 1 << 2;
+  static const isNonNullableByDefaultFlag = 1 << 3;
 
   ObjectHandle importUri;
   final int flags;
@@ -77,6 +78,9 @@
     if ((flags & hasExtensionsFlag) != 0) {
       sb.writeln('    extensions: $extensionUris');
     }
+    if ((flags & isNonNullableByDefaultFlag) != 0) {
+      sb.writeln('    is nnbd');
+    }
     sb.writeln();
     for (var cls in classes) {
       sb.write(cls);
@@ -1194,7 +1198,7 @@
 
 class Component {
   static const int magicValue = 0x44424332; // 'DBC2'
-  static const int numSections = 13;
+  static const int numSections = 14;
   static const int sectionAlignment = 4;
 
   //  UInt32 magic, version, numSections x (numItems, offset)
@@ -1213,6 +1217,7 @@
   final Map<Uri, SourceFile> uriToSource = <Uri, SourceFile>{};
   final List<LocalVariableTable> localVariables = <LocalVariableTable>[];
   final List<AnnotationsDeclaration> annotations = <AnnotationsDeclaration>[];
+  Set<String> protectedNames;
   ObjectHandle mainLibrary;
 
   Component(this.version)
@@ -1225,6 +1230,13 @@
     // Write sections to their own buffers in reverse order as section may
     // reference data structures from successor sections by offsets.
 
+    final protectedNamesWriter = new BufferedWriter.fromWriter(writer);
+    if (protectedNames != null && protectedNames.isNotEmpty) {
+      for (var name in protectedNames) {
+        protectedNamesWriter.writePackedStringReference(name);
+      }
+    }
+
     final annotationsWriter = new BufferedWriter.fromWriter(writer);
     for (var annot in annotations) {
       writer.linkWriter.put(annot, annotationsWriter.offset);
@@ -1317,6 +1329,8 @@
       new _Section(lineStarts.length, lineStartsWriter),
       new _Section(localVariables.length, localVariablesWriter),
       new _Section(annotations.length, annotationsWriter),
+      new _Section(protectedNames != null ? protectedNames.length : 0,
+          protectedNamesWriter),
     ];
     assert(sections.length == numSections);
 
@@ -1405,6 +1419,9 @@
     final annotationsNum = reader.readUInt32();
     final annotationsOffset = reader.readUInt32();
 
+    final protectedNamesNum = reader.readUInt32();
+    final protectedNamesOffset = reader.readUInt32();
+
     reader.offset = start + stringTableOffset;
     stringTable = new StringTable.read(reader);
     reader.stringReader = stringTable;
@@ -1416,6 +1433,14 @@
     // Read sections in the reverse order as section may reference
     // successor sections by offsets.
 
+    if (protectedNamesNum != 0) {
+      protectedNames = new Set<String>();
+      reader.offset = start + protectedNamesOffset;
+      for (int i = 0; i < protectedNamesNum; ++i) {
+        protectedNames.add(reader.readPackedStringReference());
+      }
+    }
+
     final annotationsStart = start + annotationsOffset;
     reader.offset = annotationsStart;
     for (int i = 0; i < annotationsNum; ++i) {
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index cc6d413..bb7f76d 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -41,6 +41,7 @@
         hasFreeTypeParameters,
         hasInstantiatorTypeArguments,
         isAllDynamic,
+        isCallThroughGetter,
         isInstantiatedInterfaceCall,
         isUncheckedCall,
         isUncheckedClosureCall;
@@ -58,6 +59,8 @@
     show DirectCallMetadata, DirectCallMetadataRepository;
 import '../metadata/inferred_type.dart'
     show InferredType, InferredTypeMetadataRepository;
+import '../metadata/obfuscation_prohibitions.dart'
+    show ObfuscationProhibitionsMetadataRepository;
 import '../metadata/procedure_attributes.dart'
     show ProcedureAttributesMetadata, ProcedureAttributesMetadataRepository;
 
@@ -113,6 +116,9 @@
 }
 
 class BytecodeGenerator extends RecursiveVisitor<Null> {
+  static final Name callName = new Name('call');
+  static final Name noSuchMethodName = new Name('noSuchMethod');
+
   final CoreTypes coreTypes;
   final ClassHierarchy hierarchy;
   final TypeEnvironment typeEnvironment;
@@ -189,6 +195,14 @@
 
     inferredTypeMetadata = component
         .metadata[InferredTypeMetadataRepository.repositoryTag]?.mapping;
+
+    final obfuscationProhibitionsMetadataRepository = component
+        .metadata[ObfuscationProhibitionsMetadataRepository.repositoryTag];
+    if (obfuscationProhibitionsMetadataRepository != null) {
+      bytecodeComponent.protectedNames =
+          obfuscationProhibitionsMetadataRepository
+              .mapping[component]?.protectedNames;
+    }
   }
 
   @override
@@ -245,7 +259,7 @@
         source = bytecodeComponent.uriToSource[uri];
         if (source == null) {
           final importUri =
-              objectTable.getNameHandle(null, astSource.importUri.toString());
+              objectTable.getConstStringHandle(astSource.importUri.toString());
           source = new SourceFile(importUri);
           bytecodeComponent.sourceFiles.add(source);
           bytecodeComponent.uriToSource[uri] = source;
@@ -272,7 +286,7 @@
   LibraryDeclaration getLibraryDeclaration(
       Library library, List<ClassDeclaration> classes) {
     final importUri =
-        objectTable.getNameHandle(null, library.importUri.toString());
+        objectTable.getConstStringHandle(library.importUri.toString());
     int flags = 0;
     for (var dependency in library.dependencies) {
       final targetLibrary = dependency.targetLibrary;
@@ -283,13 +297,16 @@
         flags |= LibraryDeclaration.usesDartFfiFlag;
       }
     }
-    final name = objectTable.getNameHandle(null, library.name ?? '');
+    final name = objectTable.getPublicNameHandle(library.name ?? '');
     final script = getScript(library.fileUri, true);
     final extensionUris =
-        objectTable.getPublicNameHandles(getNativeExtensionUris(library));
+        objectTable.getConstStringHandles(getNativeExtensionUris(library));
     if (extensionUris.isNotEmpty) {
       flags |= LibraryDeclaration.hasExtensionsFlag;
     }
+    if (library.isNonNullableByDefault) {
+      flags |= LibraryDeclaration.isNonNullableByDefaultFlag;
+    }
     return new LibraryDeclaration(
         importUri, flags, name, script, extensionUris, classes);
   }
@@ -373,7 +390,7 @@
       }
     }
 
-    final nameHandle = objectTable.getNameHandle(null, topLevelClassName);
+    final nameHandle = objectTable.getPublicNameHandle(topLevelClassName);
     final script = getScript(library.fileUri, true);
 
     final classDeclaration = new ClassDeclaration(
@@ -703,7 +720,7 @@
         flags |= FunctionDeclaration.isExternalFlag;
       } else {
         flags |= FunctionDeclaration.isNativeFlag;
-        nativeName = objectTable.getNameHandle(null, externalName);
+        nativeName = objectTable.getConstStringHandle(externalName);
       }
     }
     int position = TreeNode.noOffset;
@@ -1079,14 +1096,28 @@
   }
 
   void _genConstructorInitializers(Constructor node) {
-    final bool isRedirecting =
-        node.initializers.any((init) => init is RedirectingInitializer);
+    bool isRedirecting = false;
+    Set<Field> initializedInInitializersList = new Set<Field>();
+    for (var initializer in node.initializers) {
+      if (initializer is RedirectingInitializer) {
+        isRedirecting = true;
+      } else if (initializer is FieldInitializer) {
+        initializedInInitializersList.add(initializer.field);
+      }
+    }
 
     if (!isRedirecting) {
       initializedFields = new Set<Field>();
       for (var field in node.enclosingClass.fields) {
         if (!field.isStatic && field.initializer != null) {
-          _genFieldInitializer(field, field.initializer);
+          if (initializedInInitializersList.contains(field)) {
+            // Do not store a value into the field as it is going to be
+            // overwritten by initializers list.
+            _generateNode(field.initializer);
+            asm.emitDrop1();
+          } else {
+            _genFieldInitializer(field, field.initializer);
+          }
         }
       }
     }
@@ -1417,18 +1448,6 @@
     return negated;
   }
 
-  void _genJumpIfFalse(bool negated, Label dest) {
-    if (negated) {
-      asm.emitJumpIfTrue(dest);
-    } else {
-      asm.emitJumpIfFalse(dest);
-    }
-  }
-
-  void _genJumpIfTrue(bool negated, Label dest) {
-    _genJumpIfFalse(!negated, dest);
-  }
-
   /// Returns value of the given expression if it is a bool constant.
   /// Otherwise, returns `null`.
   bool _constantConditionValue(Expression condition) {
@@ -1484,11 +1503,33 @@
       }
       return;
     }
-    bool negated = _genCondition(condition);
-    if (value) {
-      _genJumpIfTrue(negated, dest);
+    if (condition is Not) {
+      _genConditionAndJumpIf(condition.operand, !value, dest);
+    } else if (condition is LogicalExpression) {
+      assert(condition.operator == '||' || condition.operator == '&&');
+      final isOR = (condition.operator == '||');
+
+      Label shortCircuit, done;
+      if (isOR == value) {
+        shortCircuit = dest;
+      } else {
+        shortCircuit = done = new Label();
+      }
+      _genConditionAndJumpIf(condition.left, isOR, shortCircuit);
+      _genConditionAndJumpIf(condition.right, value, dest);
+      if (done != null) {
+        asm.bind(done);
+      }
     } else {
-      _genJumpIfFalse(negated, dest);
+      bool negated = _genCondition(condition);
+      if (negated) {
+        value = !value;
+      }
+      if (value) {
+        asm.emitJumpIfTrue(dest);
+      } else {
+        asm.emitJumpIfFalse(dest);
+      }
     }
   }
 
@@ -1808,7 +1849,7 @@
         assert(numOptionalNamed != 0);
         for (int i = 0; i < numOptionalNamed; i++) {
           final param = locals.sortedNamedParameters[i];
-          asm.emitLoadConstant(numFixed + i, cp.addString(param.name));
+          asm.emitLoadConstant(numFixed + i, cp.addName(param.name));
           asm.emitLoadConstant(numFixed + i, _getDefaultParamConstIndex(param));
         }
       }
@@ -2013,7 +2054,7 @@
         isCaptured
             ? locals.getVarIndexInContext(variable)
             : locals.getVarIndexInFrame(variable),
-        cp.addString(variable.name),
+        cp.addName(variable.name),
         cp.addType(variable.type),
         variable.fileOffset,
         initializedPosition);
@@ -2259,7 +2300,7 @@
     _genPushInstantiatorAndFunctionTypeArguments([type, bound]);
     asm.emitPushConstant(cp.addType(type));
     asm.emitPushConstant(cp.addType(bound));
-    asm.emitPushConstant(cp.addString(typeParam.name));
+    asm.emitPushConstant(cp.addName(typeParam.name));
     asm.emitAssertSubtype();
   }
 
@@ -2277,11 +2318,12 @@
     asm.emitDrop1();
   }
 
-  void _genAssertAssignable(DartType type, {String name = ''}) {
+  void _genAssertAssignable(DartType type, {String name, String message}) {
     assert(!typeEnvironment.isTop(type));
     asm.emitPushConstant(cp.addType(type));
     _genPushInstantiatorAndFunctionTypeArguments([type]);
-    asm.emitPushConstant(cp.addString(name));
+    asm.emitPushConstant(
+        name != null ? cp.addName(name) : cp.addString(message));
     bool isIntOk = typeEnvironment.isSubtypeOf(
         typeEnvironment.coreTypes.intLegacyRawType,
         type,
@@ -2434,11 +2476,11 @@
 
     final List<NameAndType> parameters = <NameAndType>[];
     for (var v in function.positionalParameters) {
-      parameters.add(new NameAndType(objectTable.getNameHandle(null, v.name),
+      parameters.add(new NameAndType(objectTable.getPublicNameHandle(v.name),
           objectTable.getHandle(v.type)));
     }
     for (var v in function.namedParameters) {
-      parameters.add(new NameAndType(objectTable.getNameHandle(null, v.name),
+      parameters.add(new NameAndType(objectTable.getPublicNameHandle(v.name),
           objectTable.getHandle(v.type)));
     }
     if (function.requiredParameterCount != parameters.length) {
@@ -2458,7 +2500,7 @@
     return new ClosureDeclaration(
         flags,
         objectTable.getHandle(parent),
-        objectTable.getNameHandle(null, name),
+        objectTable.getPublicNameHandle(name),
         position,
         endPosition,
         typeParams,
@@ -2741,7 +2783,7 @@
     _genPushReceiver();
 
     // Argument 0 for _allocateInvocationMirror(): function name.
-    asm.emitPushConstant(cp.addString(name));
+    asm.emitPushConstant(cp.addName(name));
 
     // Argument 1 for _allocateInvocationMirror(): arguments descriptor.
     asm.emitPushConstant(argDescCpIndex);
@@ -2756,7 +2798,7 @@
         allocateInvocationMirror, objectTable.getArgDescHandle(4), 4);
 
     final Member target = hierarchy.getDispatchTarget(
-        enclosingClass.superclass, new Name('noSuchMethod'));
+        enclosingClass.superclass, noSuchMethodName);
     assert(target != null);
     _genDirectCall(target, objectTable.getArgDescHandle(2), 2);
   }
@@ -2774,7 +2816,8 @@
       return;
     }
 
-    _genAssertAssignable(type, name: node.isTypeError ? '' : symbolForTypeCast);
+    _genAssertAssignable(type,
+        message: node.isTypeError ? '' : symbolForTypeCast);
   }
 
   @override
@@ -3125,7 +3168,7 @@
     final isUnchecked = invocationKind != InvocationKind.getter &&
         _isUncheckedCall(node, interfaceTarget, receiver);
 
-    if (inferredTypeMetadata != null) {
+    if (inferredTypeMetadata != null && node != null) {
       _appendInferredType(node, asm.offset);
     }
 
@@ -3151,6 +3194,58 @@
     }
   }
 
+  /// Generates bytecode for o.foo(a0, ..., aN) call where o.foo is a
+  /// field or getter.
+  void _genCallThroughGetter(MethodInvocation node, int totalArgCount) {
+    final arguments = node.arguments;
+    if (arguments.types.isNotEmpty) {
+      _genTypeArguments(arguments.types);
+    }
+
+    // Keep order of evaluation: o, a0, .., aN, o.foo, o.foo.call(a0, ..., aN).
+    final receiver = node.receiver;
+    _generateNode(receiver);
+    final receiverTemp = locals.tempIndexInFrame(node, tempIndex: 0);
+    final checkForNull =
+        node.interfaceTarget.enclosingClass != coreTypes.objectClass;
+    if (checkForNull) {
+      asm.emitStoreLocal(receiverTemp);
+    }
+
+    int count = 0;
+    for (var arg in arguments.positional) {
+      _generateNode(arg);
+      asm.emitPopLocal(locals.tempIndexInFrame(node, tempIndex: count + 1));
+      ++count;
+    }
+    for (var arg in arguments.named) {
+      _generateNode(arg.value);
+      asm.emitPopLocal(locals.tempIndexInFrame(node, tempIndex: count + 1));
+      ++count;
+    }
+
+    // Check receiver for null before calling getter to report
+    // correct noSuchMethod for method call.
+    if (checkForNull) {
+      asm.emitPush(receiverTemp);
+      asm.emitCheckReceiverForNull(
+          cp.addSelectorName(node.name, InvocationKind.method));
+    }
+
+    _genInstanceCall(null, InvocationKind.getter, node.interfaceTarget,
+        node.name, receiver, 1, objectTable.getArgDescHandle(1));
+
+    for (int i = 0; i < count; ++i) {
+      asm.emitPush(locals.tempIndexInFrame(node, tempIndex: i + 1));
+    }
+
+    final argDesc =
+        objectTable.getArgDescHandleByArguments(arguments, hasReceiver: true);
+
+    _genInstanceCall(node, InvocationKind.method, null, callName, null,
+        totalArgCount, argDesc);
+  }
+
   @override
   visitMethodInvocation(MethodInvocation node) {
     final directCall =
@@ -3180,6 +3275,13 @@
       return;
     }
 
+    final Member interfaceTarget = node.interfaceTarget;
+    if (isCallThroughGetter(interfaceTarget)) {
+      assert(directCall == null);
+      _genCallThroughGetter(node, totalArgCount);
+      return;
+    }
+
     if (directCall != null && directCall.checkReceiverForNull) {
       final int receiverTemp = locals.tempIndexInFrame(node);
       _genArguments(node.receiver, args, storeReceiverToLocal: receiverTemp);
@@ -3190,15 +3292,6 @@
       _genArguments(node.receiver, args);
     }
 
-    Member interfaceTarget = node.interfaceTarget;
-    if (interfaceTarget is Field ||
-        interfaceTarget is Procedure && interfaceTarget.isGetter) {
-      // Call via field or getter. Treat it as a dynamic call because
-      // interface target doesn't fully represent what is being called.
-      assert(directCall == null);
-      interfaceTarget = null;
-    }
-
     final argDesc =
         objectTable.getArgDescHandleByArguments(args, hasReceiver: true);
 
@@ -3444,6 +3537,19 @@
       _generateNode(args.positional.single);
       return;
     }
+    if (!options.causalAsyncStacks &&
+        target == coreTypes.asyncStackTraceHelperProcedure) {
+      // Eliminate calls to _asyncStackTraceHelper as causal async stacks are
+      // disabled. These calls are inserted by async transformation
+      // (pkg/kernel/lib/transformations/continuation.dart), but they should be
+      // consistent with _setAsyncThreadStackTrace and
+      // _clearAsyncThreadStackTrace calls generated by bytecode generator.
+      //
+      // Push null as _asyncStackTraceHelper call should leave result
+      // on the stack.
+      asm.emitPushNull();
+      return;
+    }
     if (target.isFactory) {
       final constructedClass = target.enclosingClass;
       if (hasInstantiatorTypeArguments(constructedClass)) {
@@ -3779,7 +3885,7 @@
         cp.addInterfaceCall(InvocationKind.method, iteratorMoveNext,
             objectTable.getArgDescHandle(1)),
         1);
-    _genJumpIfFalse(/* negated = */ false, done);
+    asm.emitJumpIfFalse(done);
 
     _enterScope(node);
     _recordSourcePosition(node.bodyOffset);
@@ -3953,13 +4059,13 @@
         final savedSourcePosition = asm.currentSourcePosition;
         for (int i = 0; i < switchCase.expressions.length; ++i) {
           _recordSourcePosition(switchCase.expressionOffsets[i]);
-          asm.emitPush(temp);
           _genPushConstExpr(switchCase.expressions[i]);
+          asm.emitPush(temp);
           asm.emitInterfaceCall(
               cp.addInterfaceCall(
                   InvocationKind.method, coreTypes.objectEquals, equalsArgDesc),
               2);
-          _genJumpIfTrue(/* negated = */ false, caseLabel);
+          asm.emitJumpIfTrue(caseLabel);
         }
         asm.currentSourcePosition = savedSourcePosition;
       }
@@ -4135,7 +4241,7 @@
         _genInstanceOf(catchClause.guard);
 
         skipCatch = new Label();
-        _genJumpIfFalse(/* negated = */ false, skipCatch);
+        asm.emitJumpIfFalse(skipCatch);
       }
 
       _enterScope(catchClause);
diff --git a/pkg/vm/lib/bytecode/generics.dart b/pkg/vm/lib/bytecode/generics.dart
index 4d3607d..5e60ef1 100644
--- a/pkg/vm/lib/bytecode/generics.dart
+++ b/pkg/vm/lib/bytecode/generics.dart
@@ -286,3 +286,9 @@
     node.name.name == 'call' &&
     getStaticType(node.receiver, typeEnvironment) is FunctionType &&
     !options.avoidClosureCallInstructions;
+
+/// Returns true if [MethodInvocation] node with given [interfaceTarget] is
+/// a call through field or getter.
+bool isCallThroughGetter(Member interfaceTarget) =>
+    interfaceTarget is Field ||
+    interfaceTarget is Procedure && interfaceTarget.isGetter;
diff --git a/pkg/vm/lib/bytecode/local_vars.dart b/pkg/vm/lib/bytecode/local_vars.dart
index 884c149..18074aa 100644
--- a/pkg/vm/lib/bytecode/local_vars.dart
+++ b/pkg/vm/lib/bytecode/local_vars.dart
@@ -1211,6 +1211,9 @@
     int numTemps = 0;
     if (isUncheckedClosureCall(node, locals.typeEnvironment, locals.options)) {
       numTemps = 1;
+    } else if (isCallThroughGetter(node.interfaceTarget)) {
+      final args = node.arguments;
+      numTemps = 1 + args.positional.length + args.named.length;
     } else if (locals.directCallMetadata != null) {
       final directCall = locals.directCallMetadata[node];
       if (directCall != null && directCall.checkReceiverForNull) {
diff --git a/pkg/vm/lib/bytecode/object_table.dart b/pkg/vm/lib/bytecode/object_table.dart
index 5eb9122..ca1e1c3 100644
--- a/pkg/vm/lib/bytecode/object_table.dart
+++ b/pkg/vm/lib/bytecode/object_table.dart
@@ -308,6 +308,7 @@
   kBool,
   kSymbol,
   kTearOffInstantiation,
+  kString,
 }
 
 enum TypeTag {
@@ -394,7 +395,9 @@
       case ObjectKind.kClosure:
         return new _ClosureHandle._empty();
       case ObjectKind.kName:
-        return new _NameHandle._empty();
+        return ((flags & _NameHandle.flagIsPublic) != 0)
+            ? new _PublicNameHandle._empty()
+            : _PrivateNameHandle._empty();
       case ObjectKind.kTypeArguments:
         return new _TypeArgumentsHandle._empty();
       case ObjectKind.kConstObject:
@@ -478,7 +481,7 @@
 }
 
 class _LibraryHandle extends ObjectHandle {
-  _NameHandle uri;
+  _ConstObjectHandle uri;
 
   _LibraryHandle._empty();
 
@@ -509,7 +512,7 @@
   bool operator ==(other) => other is _LibraryHandle && this.uri == other.uri;
 
   @override
-  String toString() => uri.name;
+  String toString() => uri.value;
 }
 
 class _ClassHandle extends ObjectHandle {
@@ -1102,18 +1105,65 @@
   }
 }
 
-class _NameHandle extends ObjectHandle {
-  _LibraryHandle library;
-  String name;
+abstract class _NameHandle extends ObjectHandle {
+  static const int flagIsPublic = ObjectHandle.flagBit0;
 
-  _NameHandle._empty();
-
-  _NameHandle(this.library, this.name);
+  String get name;
 
   @override
   ObjectKind get kind => ObjectKind.kName;
 
   @override
+  void indexStrings(StringWriter strings) {
+    strings.put(name);
+  }
+
+  @override
+  String toString() => "'$name'";
+}
+
+class _PublicNameHandle extends _NameHandle {
+  String name;
+
+  _PublicNameHandle._empty();
+
+  _PublicNameHandle(this.name);
+
+  @override
+  int get flags => _NameHandle.flagIsPublic;
+
+  @override
+  void writeContents(BufferedWriter writer) {
+    writer.writePackedStringReference(name);
+  }
+
+  @override
+  void readContents(BufferedReader reader) {
+    name = reader.readPackedStringReference();
+  }
+
+  @override
+  int get hashCode => name.hashCode;
+
+  @override
+  bool operator ==(other) =>
+      other is _PublicNameHandle && this.name == other.name;
+
+  @override
+  String toString() => "'$name'";
+}
+
+class _PrivateNameHandle extends _NameHandle {
+  _LibraryHandle library;
+  String name;
+
+  _PrivateNameHandle._empty();
+
+  _PrivateNameHandle(this.library, this.name) {
+    assert(library != null);
+  }
+
+  @override
   void writeContents(BufferedWriter writer) {
     writer.writePackedObject(library);
     writer.writePackedStringReference(name);
@@ -1127,14 +1177,7 @@
 
   @override
   void accountUsesForObjectCopies(int numCopies) {
-    if (library != null) {
-      library._useCount += numCopies;
-    }
-  }
-
-  @override
-  void indexStrings(StringWriter strings) {
-    strings.put(name);
+    library._useCount += numCopies;
   }
 
   @override
@@ -1142,7 +1185,7 @@
 
   @override
   bool operator ==(other) =>
-      other is _NameHandle &&
+      other is _PrivateNameHandle &&
       this.name == other.name &&
       this.library == other.library;
 
@@ -1271,6 +1314,9 @@
           writer.writePackedObject(type as _TypeArgumentsHandle);
         }
         break;
+      case ConstTag.kString:
+        writer.writePackedStringReference(value as String);
+        break;
       default:
         throw 'Unexpected constant tag: $tag';
     }
@@ -1310,6 +1356,9 @@
         value = reader.readPackedObject();
         type = reader.readPackedObject();
         break;
+      case ConstTag.kString:
+        value = reader.readPackedStringReference();
+        break;
       default:
         throw 'Unexpected constant tag: $tag';
     }
@@ -1321,6 +1370,7 @@
       case ConstTag.kInt:
       case ConstTag.kDouble:
       case ConstTag.kBool:
+      case ConstTag.kString:
         break;
       case ConstTag.kInstance:
         {
@@ -1378,6 +1428,7 @@
       case ConstTag.kBool:
       case ConstTag.kTearOff:
       case ConstTag.kSymbol:
+      case ConstTag.kString:
         return _hashCode = value.hashCode;
       case ConstTag.kInstance:
         {
@@ -1410,6 +1461,7 @@
         case ConstTag.kBool:
         case ConstTag.kTearOff:
         case ConstTag.kSymbol:
+        case ConstTag.kString:
           return this.value == other.value;
         case ConstTag.kDouble:
           return this.value.compareTo(other.value) == 0;
@@ -1442,6 +1494,8 @@
         return 'const tear-off $value';
       case ConstTag.kTearOffInstantiation:
         return 'const $type $value';
+      case ConstTag.kString:
+        return "'$value'";
       default:
         throw 'Unexpected constant tag: $tag';
     }
@@ -1455,7 +1509,7 @@
   int _flags = 0;
   int numArguments;
   int numTypeArguments;
-  List<_NameHandle> argNames;
+  List<_PublicNameHandle> argNames;
 
   _ArgDescHandle._empty();
 
@@ -1496,7 +1550,7 @@
     numTypeArguments =
         ((_flags & flagHasTypeArgs) != 0) ? reader.readPackedUInt30() : 0;
     argNames = ((_flags & flagHasNamedArgs) != 0)
-        ? reader.readPackedList<_NameHandle>()
+        ? reader.readPackedList<_PublicNameHandle>()
         : null;
   }
 
@@ -1614,6 +1668,8 @@
   final Map<ObjectHandle, ObjectHandle> _canonicalizationCache =
       <ObjectHandle, ObjectHandle>{};
   final Map<Node, ObjectHandle> _nodeCache = <Node, ObjectHandle>{};
+  final Map<String, _PublicNameHandle> _publicNames =
+      <String, _PublicNameHandle>{};
   List<ObjectHandle> _indexTable;
   _TypeHandle _dynamicType;
   _TypeHandle _voidType;
@@ -1675,19 +1731,46 @@
     return name;
   }
 
-  ObjectHandle getNameHandle(Library library, String name) {
+  ObjectHandle getPublicNameHandle(String name) {
     assert(name != null);
-    final libraryHandle = library != null ? getHandle(library) : null;
-    return getOrAddObject(new _NameHandle(libraryHandle, name));
+    _PublicNameHandle handle = _publicNames[name];
+    if (handle == null) {
+      handle = getOrAddObject(new _PublicNameHandle(name));
+      _publicNames[name] = handle;
+    }
+    return handle;
   }
 
-  List<_NameHandle> getPublicNameHandles(List<String> names) {
-    if (names.isEmpty) {
-      return const <_NameHandle>[];
+  ObjectHandle getNameHandle(Library library, String name) {
+    if (library == null) {
+      return getPublicNameHandle(name);
     }
-    final handles = new List<_NameHandle>(names.length);
+    assert(name != null);
+    final libraryHandle = library != null ? getHandle(library) : null;
+    return getOrAddObject(new _PrivateNameHandle(libraryHandle, name));
+  }
+
+  List<_PublicNameHandle> getPublicNameHandles(List<String> names) {
+    if (names.isEmpty) {
+      return const <_PublicNameHandle>[];
+    }
+    final handles = new List<_PublicNameHandle>(names.length);
     for (int i = 0; i < names.length; ++i) {
-      handles[i] = getNameHandle(null, names[i]);
+      handles[i] = getPublicNameHandle(names[i]);
+    }
+    return handles;
+  }
+
+  ObjectHandle getConstStringHandle(String value) =>
+      getOrAddObject(new _ConstObjectHandle(ConstTag.kString, value));
+
+  List<ObjectHandle> getConstStringHandles(List<String> values) {
+    if (values.isEmpty) {
+      return const <ObjectHandle>[];
+    }
+    final handles = new List<ObjectHandle>(values.length);
+    for (int i = 0; i < values.length; ++i) {
+      handles[i] = getConstStringHandle(values[i]);
     }
     return handles;
   }
@@ -1700,7 +1783,7 @@
 
   ObjectHandle getTopLevelClassHandle(Library library) {
     final libraryHandle = getHandle(library);
-    final name = getNameHandle(null, topLevelClassName);
+    final name = getPublicNameHandle(topLevelClassName);
     return getOrAddObject(new _ClassHandle(libraryHandle, name));
   }
 
@@ -1743,12 +1826,12 @@
 
   ObjectHandle getArgDescHandleByArguments(Arguments args,
       {bool hasReceiver: false, bool isFactory: false}) {
-    List<_NameHandle> argNames = const <_NameHandle>[];
+    List<_PublicNameHandle> argNames = const <_PublicNameHandle>[];
     final namedArguments = args.named;
     if (namedArguments.isNotEmpty) {
-      argNames = new List<_NameHandle>(namedArguments.length);
+      argNames = new List<_PublicNameHandle>(namedArguments.length);
       for (int i = 0; i < namedArguments.length; ++i) {
-        argNames[i] = getNameHandle(null, namedArguments[i].name);
+        argNames[i] = getPublicNameHandle(namedArguments[i].name);
       }
     }
     final int numArguments = args.positional.length +
@@ -1765,7 +1848,7 @@
   }
 
   ObjectHandle getScriptHandle(Uri uri, SourceFile source) {
-    ObjectHandle uriHandle = getNameHandle(null, uri.toString());
+    ObjectHandle uriHandle = getPublicNameHandle(uri.toString());
     _ScriptHandle handle = getOrAddObject(new _ScriptHandle(uriHandle, source));
     if (handle.source == null && source != null) {
       handle.source = source;
@@ -1780,7 +1863,7 @@
     final namesAndBounds = new List<NameAndType>();
     for (TypeParameter tp in typeParams) {
       namesAndBounds.add(
-          new NameAndType(getNameHandle(null, tp.name), getHandle(tp.bound)));
+          new NameAndType(getPublicNameHandle(tp.name), getHandle(tp.bound)));
     }
     return namesAndBounds;
   }
@@ -1947,15 +2030,16 @@
 
   @override
   ObjectHandle visitLibrary(Library node) {
-    final uri = objectTable.getNameHandle(null, node.importUri.toString());
+    final uri = objectTable.getConstStringHandle(node.importUri.toString());
     return objectTable.getOrAddObject(new _LibraryHandle(uri));
   }
 
   @override
   ObjectHandle visitClass(Class node) {
     final ObjectHandle library = objectTable.getHandle(node.enclosingLibrary);
-    final name = objectTable.getOrAddObject(
-        new _NameHandle(node.name.startsWith('_') ? library : null, node.name));
+    final name = node.name.startsWith('_')
+        ? objectTable.getOrAddObject(new _PrivateNameHandle(library, node.name))
+        : objectTable.getPublicNameHandle(node.name);
     return objectTable.getOrAddObject(new _ClassHandle(library, name));
   }
 
@@ -2083,7 +2167,7 @@
     final namedParams = new List<NameAndType>();
     for (var param in node.namedParameters) {
       namedParams.add(new NameAndType(
-          objectTable.getNameHandle(null, param.name),
+          objectTable.getPublicNameHandle(param.name),
           objectTable.getHandle(param.type)));
     }
     final returnType = objectTable.getHandle(node.returnType);
@@ -2123,7 +2207,7 @@
 
   @override
   ObjectHandle visitStringConstant(StringConstant node) =>
-      objectTable.getNameHandle(null, node.value);
+      objectTable.getConstStringHandle(node.value);
 
   @override
   ObjectHandle visitSymbolConstant(SymbolConstant node) =>
diff --git a/pkg/vm/lib/incremental_compiler.dart b/pkg/vm/lib/incremental_compiler.dart
index 765991b..f26628b 100644
--- a/pkg/vm/lib/incremental_compiler.dart
+++ b/pkg/vm/lib/incremental_compiler.dart
@@ -19,6 +19,7 @@
 /// accepted.
 class IncrementalCompiler {
   IncrementalKernelGenerator _generator;
+  IncrementalSerializer incrementalSerializer;
 
   // Component that reflect the state that was most recently accepted by the
   // client. Is [null], if no compilation results were accepted by the client.
@@ -34,9 +35,12 @@
   Uri get entryPoint => _entryPoint;
 
   IncrementalCompiler(this._compilerOptions, this._entryPoint,
-      {this.initializeFromDillUri}) {
-    _generator = new IncrementalKernelGenerator(
-        _compilerOptions, _entryPoint, initializeFromDillUri);
+      {this.initializeFromDillUri, bool incrementalSerialization: true}) {
+    if (incrementalSerialization) {
+      incrementalSerializer = new IncrementalSerializer();
+    }
+    _generator = new IncrementalKernelGenerator(_compilerOptions, _entryPoint,
+        initializeFromDillUri, false, incrementalSerializer);
     _pendingDeltas = <Component>[];
   }
 
@@ -127,8 +131,11 @@
     _pendingDeltas.clear();
     // Need to reset and warm up compiler so that expression evaluation requests
     // are processed in that known good state.
-    _generator = new IncrementalKernelGenerator.fromComponent(
-        _compilerOptions, _entryPoint, _lastKnownGood);
+    if (incrementalSerializer != null) {
+      incrementalSerializer = new IncrementalSerializer();
+    }
+    _generator = new IncrementalKernelGenerator.fromComponent(_compilerOptions,
+        _entryPoint, _lastKnownGood, false, incrementalSerializer);
     await _generator.computeDelta(entryPoints: [_entryPoint]);
   }
 
diff --git a/pkg/vm/lib/kernel_front_end.dart b/pkg/vm/lib/kernel_front_end.dart
index c5e5d89..2963159 100644
--- a/pkg/vm/lib/kernel_front_end.dart
+++ b/pkg/vm/lib/kernel_front_end.dart
@@ -250,6 +250,8 @@
       mainUri,
       compilerOptions,
       results.component,
+      results.coreTypes,
+      results.classHierarchy,
       outputFileName,
       genBytecode: genBytecode,
       bytecodeOptions: bytecodeOptions,
@@ -264,9 +266,12 @@
 /// collection of compiled sources.
 class KernelCompilationResults {
   final Component component;
+  final ClassHierarchy classHierarchy;
+  final CoreTypes coreTypes;
   final Iterable<Uri> compiledSources;
 
-  KernelCompilationResults(this.component, this.compiledSources);
+  KernelCompilationResults(this.component, this.classHierarchy, this.coreTypes,
+      this.compiledSources);
 }
 
 /// Generates a kernel representation of the program whose main library is in
@@ -290,6 +295,7 @@
 
   setVMEnvironmentDefines(environmentDefines, options);
   CompilerResult compilerResult = await kernelForProgram(source, options);
+
   Component component = compilerResult?.component;
   final compiledSources = component?.uriToSource?.keys;
 
@@ -307,7 +313,10 @@
 
   if (genBytecode && !errorDetector.hasCompilationErrors && component != null) {
     await runWithFrontEndCompilerContext(source, options, component, () {
-      generateBytecode(component, options: bytecodeOptions);
+      generateBytecode(component,
+          hierarchy: compilerResult.classHierarchy,
+          coreTypes: compilerResult.coreTypes,
+          options: bytecodeOptions);
     });
 
     if (dropAST) {
@@ -318,7 +327,8 @@
   // Restore error handler (in case 'options' are reused).
   options.onDiagnostic = errorDetector.previousErrorHandler;
 
-  return new KernelCompilationResults(component, compiledSources);
+  return new KernelCompilationResults(component, compilerResult?.classHierarchy,
+      compilerResult?.coreTypes, compiledSources);
 }
 
 void setVMEnvironmentDefines(
@@ -590,6 +600,8 @@
   Uri source,
   CompilerOptions compilerOptions,
   Component component,
+  CoreTypes coreTypes,
+  ClassHierarchy hierarchy,
   String outputFileName, {
   bool genBytecode: false,
   BytecodeOptions bytecodeOptions,
@@ -599,14 +611,6 @@
     BytecodeSizeStatistics.reset();
   }
 
-  ClassHierarchy hierarchy;
-  if (genBytecode) {
-    // Calculating class hierarchy is an expensive operation.
-    // Calculate it once and reuse while generating bytecode for each package.
-    hierarchy =
-        new ClassHierarchy(component, onAmbiguousSupertypes: (cls, a, b) {});
-  }
-
   final packages = new List<String>();
   await runWithFrontEndCompilerContext(source, compilerOptions, component,
       () async {
@@ -621,7 +625,8 @@
         generateBytecode(partComponent,
             options: bytecodeOptions,
             libraries: libraries,
-            hierarchy: hierarchy);
+            hierarchy: hierarchy,
+            coreTypes: coreTypes);
 
         if (dropAST) {
           partComponent = createFreshComponentWithBytecode(partComponent);
diff --git a/pkg/vm/lib/target/install.dart b/pkg/vm/lib/target/install.dart
index d6d40b2..4973418 100644
--- a/pkg/vm/lib/target/install.dart
+++ b/pkg/vm/lib/target/install.dart
@@ -5,24 +5,20 @@
 library vm.target.install;
 
 import 'package:kernel/target/targets.dart' show targets, TargetFlags;
-
 import 'package:vm/target/dart_runner.dart' show DartRunnerTarget;
-
 import 'package:vm/target/flutter.dart' show FlutterTarget;
-
 import 'package:vm/target/flutter_runner.dart' show FlutterRunnerTarget;
-
 import 'package:vm/target/vm.dart' show VmTarget;
 
 bool _installed = false;
 
 void installAdditionalTargets() {
   if (!_installed) {
-    targets["dart_runner"] = (TargetFlags flags) => new DartRunnerTarget(flags);
-    targets["flutter"] = (TargetFlags flags) => new FlutterTarget(flags);
+    targets["dart_runner"] = (TargetFlags flags) => DartRunnerTarget(flags);
+    targets["flutter"] = (TargetFlags flags) => FlutterTarget(flags);
     targets["flutter_runner"] =
-        (TargetFlags flags) => new FlutterRunnerTarget(flags);
-    targets["vm"] = (TargetFlags flags) => new VmTarget(flags);
+        (TargetFlags flags) => FlutterRunnerTarget(flags);
+    targets["vm"] = (TargetFlags flags) => VmTarget(flags);
     _installed = true;
   }
 }
diff --git a/pkg/vm/lib/transformations/ffi.dart b/pkg/vm/lib/transformations/ffi.dart
index c4e6800..e807469 100644
--- a/pkg/vm/lib/transformations/ffi.dart
+++ b/pkg/vm/lib/transformations/ffi.dart
@@ -154,6 +154,22 @@
   Abi.wordSize32Align64: {},
 };
 
+/// Load, store, and elementAt are rewired to their static type for these types.
+const List<NativeType> optimizedTypes = [
+  NativeType.kInt8,
+  NativeType.kInt16,
+  NativeType.kInt32,
+  NativeType.kInt64,
+  NativeType.kUint8,
+  NativeType.kUint16,
+  NativeType.kUint32,
+  NativeType.kUnit64,
+  NativeType.kIntptr,
+  NativeType.kFloat,
+  NativeType.kDouble,
+  NativeType.kPointer,
+];
+
 /// [FfiTransformer] contains logic which is shared between
 /// _FfiUseSiteTransformer and _FfiDefinitionTransformer.
 class FfiTransformer extends Transformer {
@@ -175,9 +191,8 @@
   final Class pointerClass;
   final Class structClass;
   final Procedure castMethod;
-  final Procedure loadMethod;
-  final Procedure storeMethod;
   final Procedure offsetByMethod;
+  final Procedure elementAtMethod;
   final Procedure asFunctionMethod;
   final Procedure asFunctionInternal;
   final Procedure lookupFunctionMethod;
@@ -188,6 +203,10 @@
   final Procedure abiMethod;
   final Procedure pointerFromFunctionProcedure;
   final Procedure nativeCallbackFunctionProcedure;
+  final Map<NativeType, Procedure> loadMethods;
+  final Map<NativeType, Procedure> storeMethods;
+  final Map<NativeType, Procedure> elementAtMethods;
+  final Procedure loadStructMethod;
 
   /// Classes corresponding to [NativeType], indexed by [NativeType].
   final List<Class> nativeTypesClasses;
@@ -206,12 +225,11 @@
         pointerClass = index.getClass('dart:ffi', 'Pointer'),
         structClass = index.getClass('dart:ffi', 'Struct'),
         castMethod = index.getMember('dart:ffi', 'Pointer', 'cast'),
-        loadMethod = index.getMember('dart:ffi', 'Pointer', 'load'),
-        storeMethod = index.getMember('dart:ffi', 'Pointer', 'store'),
-        offsetByMethod = index.getMember('dart:ffi', 'Pointer', 'offsetBy'),
-        addressOfField = index.getMember('dart:ffi', 'Struct', 'addressOf'),
+        offsetByMethod = index.getMember('dart:ffi', 'Pointer', '_offsetBy'),
+        elementAtMethod = index.getMember('dart:ffi', 'Pointer', 'elementAt'),
+        addressOfField = index.getMember('dart:ffi', 'Struct', '_addressOf'),
         structFromPointer =
-            index.getMember('dart:ffi', 'Struct', 'fromPointer'),
+            index.getMember('dart:ffi', 'Struct', '_fromPointer'),
         asFunctionMethod = index.getMember('dart:ffi', 'Pointer', 'asFunction'),
         asFunctionInternal =
             index.getTopLevelMember('dart:ffi', '_asFunctionInternal'),
@@ -228,7 +246,20 @@
             index.getTopLevelMember('dart:ffi', '_nativeCallbackFunction'),
         nativeTypesClasses = nativeTypeClassNames
             .map((name) => index.getClass('dart:ffi', name))
-            .toList();
+            .toList(),
+        loadMethods = Map.fromIterable(optimizedTypes, value: (t) {
+          final name = nativeTypeClassNames[t.index];
+          return index.getTopLevelMember('dart:ffi', "_load$name");
+        }),
+        storeMethods = Map.fromIterable(optimizedTypes, value: (t) {
+          final name = nativeTypeClassNames[t.index];
+          return index.getTopLevelMember('dart:ffi', "_store$name");
+        }),
+        elementAtMethods = Map.fromIterable(optimizedTypes, value: (t) {
+          final name = nativeTypeClassNames[t.index];
+          return index.getTopLevelMember('dart:ffi', "_elementAt$name");
+        }),
+        loadStructMethod = index.getTopLevelMember('dart:ffi', '_loadStruct');
 
   /// Computes the Dart type corresponding to a ffi.[NativeType], returns null
   /// if it is not a valid NativeType.
diff --git a/pkg/vm/lib/transformations/ffi_checks.md b/pkg/vm/lib/transformations/ffi_checks.md
new file mode 100644
index 0000000..ed1ce41
--- /dev/null
+++ b/pkg/vm/lib/transformations/ffi_checks.md
@@ -0,0 +1,69 @@
+# FFI static checks
+
+## Translating FFI types
+
+The FFI library defines a number of "native" types, which have corresponding
+Dart types. This is a many-to-one mapping, defined by `DartRepresentationOf` in
+`native_type.dart`.
+
+## Subtyping restrictions
+
+No class may extend, implement or mixin any classes inside the FFI library, with
+the following exception. Any class may extend (but not implement or mixin)
+`ffi.Struct`. In this case, the subclass is considered a *struct class*. No
+class may extend, implement or mixin a struct class.
+
+## Struct rules
+
+The following restrictions apply to struct classes:
+
+- A struct class must not be generic.
+- A struct class `X` must extend `Struct<X>`. That is, the type argument to the
+  superclass must be exactly the subclass itself.
+
+Some restrictions apply to fields of struct classes:
+
+- A field of a struct class must not have an initializer.
+- A field of a struct class must either have a type which is a subtype of
+  `ffi.Pointer` or else be annotated by one of the following types:
+    - `ffi.UintN` or `ffi.IntN` for any N
+    - `ffi.Float` or `ffi.Double`
+  If the field is annotated, the Dart version of the annotated type must be
+  identical to the field's declared type. Note that struct classes currently
+  must not be used as fields.
+- A field of a struct class must not have more than one annotation corresponding
+  to an FFI native type.
+
+Finally, struct classes must not have constructors with field initializers.
+
+## `fromFunction` rules
+
+The following restrictions apply to static invocations of the factory
+constructor `Pointer<T>.fromFunction(f, e)`. Dynamic invocations of this method,
+e.g. through mirrors, are runtime errors. `T` must be a subtype of
+`NativeFunction<T'>` for some `T'`. Let `F` be the Dart type which corresponds
+to static type of `T'` and `R` be the return type of `F`.
+
+- `T` must be instantiated; i.e., it must not reference any class or function
+  type parameters.
+- The static type of `f` must be a subtype of `F`.
+- Struct classes are not allowed as the top-level class in a parameter or return
+  type of `F`.
+- The static type of `e` must be a subtype of `R`.
+- `e` must be an expression which is legal in a constant context.
+- `f` must be a direct reference to a top-level method.
+- `e` must not be provided if `R` is `void` or `ffi.Pointer`.
+- `e` must be provided otherwise.
+
+## `asFunction` and `lookupFunction ` rules
+
+The following restrictions apply to statically resolved invocations of the
+instance method `Pointer<T>.asFunction<F>()` and
+`DynamicLibrary.lookupFunction<S, F>()`. Dynamic invocations of these methods,
+e.g. through mirrors or a receiver of static type `dynamic`, are runtime errors.
+`T` must be a subtype of `NativeFunction<T'>` for some `T'`. Let `F'` be the
+Dart type which corresponds to static type of `T'`/`S`.
+
+- `T`, `S` and `F` must be constants; i.e., they must not reference any class or
+  function type parameters.
+- `F'` must be a subtype of `F`.
diff --git a/pkg/vm/lib/transformations/ffi_definitions.dart b/pkg/vm/lib/transformations/ffi_definitions.dart
index 412b135..d48f9fc 100644
--- a/pkg/vm/lib/transformations/ffi_definitions.dart
+++ b/pkg/vm/lib/transformations/ffi_definitions.dart
@@ -12,8 +12,7 @@
         templateFfiFieldNoAnnotation,
         templateFfiTypeMismatch,
         templateFfiFieldInitializer,
-        templateFfiStructGeneric,
-        templateFfiWrongStructInheritance;
+        templateFfiStructGeneric;
 
 import 'package:kernel/ast.dart' hide MapEntry;
 import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
@@ -27,7 +26,7 @@
 /// Checks and elaborates the dart:ffi structs and fields.
 ///
 /// Input:
-/// class Coord extends Struct<Coord> {
+/// class Coord extends Struct {
 ///   @Double()
 ///   double x;
 ///
@@ -38,7 +37,7 @@
 /// }
 ///
 /// Output:
-/// class Coord extends Struct<Coord> {
+/// class Coord extends Struct {
 ///   Coord.#fromPointer(Pointer<Coord> coord) : super._(coord);
 ///
 ///   Pointer<Double> get _xPtr => addressOf.cast();
@@ -127,16 +126,6 @@
       // _FfiUseSiteTransformer.
       return;
     }
-
-    // A struct classes "C" must extend "Struct<C>".
-    final DartType structTypeArg = node.supertype.typeArguments[0];
-    if (structTypeArg != InterfaceType(node)) {
-      diagnosticReporter.report(
-          templateFfiWrongStructInheritance.withArguments(node.name),
-          node.fileOffset,
-          1,
-          node.location.file);
-    }
   }
 
   bool _isPointerType(Field field) {
@@ -309,6 +298,14 @@
       pointer = MethodInvocation(pointer, offsetByMethod.name,
           Arguments([_runtimeBranchOnLayout(offsets)]), offsetByMethod);
     }
+
+    final Class nativeClass = (nativeType as InterfaceType).classNode;
+    final NativeType nt = getType(nativeClass);
+    final typeArguments = [
+      if (nt == NativeType.kPointer && pointerType is InterfaceType)
+        pointerType.typeArguments[0]
+    ];
+
     final Procedure pointerGetter = Procedure(
         pointerName,
         ProcedureKind.Getter,
@@ -318,20 +315,24 @@
             returnType: pointerType));
 
     // Sample output:
-    // double get x => _xPtr.load<double>();
+    // double get x => _xPtr.value;
+    final loadMethod =
+        optimizedTypes.contains(nt) ? loadMethods[nt] : loadStructMethod;
     final Procedure getter = Procedure(
         field.name,
         ProcedureKind.Getter,
         FunctionNode(
-            ReturnStatement(MethodInvocation(
-                PropertyGet(ThisExpression(), pointerName, pointerGetter),
-                loadMethod.name,
-                Arguments([], types: [field.type]),
-                loadMethod)),
+            ReturnStatement(StaticInvocation(
+                loadMethod,
+                Arguments([
+                  PropertyGet(ThisExpression(), pointerName, pointerGetter),
+                  ConstantExpression(IntConstant(0))
+                ], types: typeArguments))),
             returnType: field.type));
 
     // Sample output:
-    // set x(double v) => _xPtr.store(v);
+    // set x(double v) { _xPtr.value = v; };
+    final storeMethod = storeMethods[nt];
     Procedure setter = null;
     if (!field.isFinal) {
       final VariableDeclaration argument =
@@ -340,11 +341,13 @@
           field.name,
           ProcedureKind.Setter,
           FunctionNode(
-              ReturnStatement(MethodInvocation(
-                  PropertyGet(ThisExpression(), pointerName, pointerGetter),
-                  storeMethod.name,
-                  Arguments([VariableGet(argument)]),
-                  storeMethod)),
+              ReturnStatement(StaticInvocation(
+                  storeMethod,
+                  Arguments([
+                    PropertyGet(ThisExpression(), pointerName, pointerGetter),
+                    ConstantExpression(IntConstant(0)),
+                    VariableGet(argument)
+                  ], types: typeArguments))),
               returnType: VoidType(),
               positionalParameters: [argument]));
     }
diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart
index d3fd73b..3cb0dfc 100644
--- a/pkg/vm/lib/transformations/ffi_use_sites.dart
+++ b/pkg/vm/lib/transformations/ffi_use_sites.dart
@@ -14,8 +14,7 @@
         templateFfiExtendsOrImplementsSealedClass,
         templateFfiNotStatic,
         templateFfiTypeInvalid,
-        templateFfiTypeMismatch,
-        templateFfiTypeUnsized;
+        templateFfiTypeMismatch;
 
 import 'package:kernel/ast.dart';
 import 'package:kernel/class_hierarchy.dart' show ClassHierarchy;
@@ -25,12 +24,7 @@
 import 'package:kernel/type_environment.dart';
 
 import 'ffi.dart'
-    show
-        ReplacedMembers,
-        NativeType,
-        kNativeTypeIntStart,
-        kNativeTypeIntEnd,
-        FfiTransformer;
+    show ReplacedMembers, NativeType, FfiTransformer, optimizedTypes;
 
 /// Checks and replaces calls to dart:ffi struct fields and methods.
 void transformLibraries(
@@ -315,32 +309,26 @@
             (nativeType as InterfaceType).typeArguments[0];
         return StaticInvocation(asFunctionInternal,
             Arguments([node.receiver], types: [dartType, nativeSignature]));
-      } else if (target == loadMethod) {
-        // TODO(dacoharkes): should load and store be generic?
-        // https://github.com/dart-lang/sdk/issues/35902
-        final DartType dartType = node.arguments.types[0];
+      } 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 nativeType = _pointerTypeGetTypeArg(pointerType);
-
-        _ensureNativeTypeValid(pointerType, node);
-        _ensureNativeTypeValid(nativeType, node, allowStructs: true);
-        _ensureNativeTypeSized(nativeType, node, target.name);
-        _ensureNativeTypeToDartType(nativeType, dartType, node,
-            allowStructs: true);
-      } else if (target == storeMethod) {
-        // TODO(dacoharkes): should load and store permitted to be generic?
-        // https://github.com/dart-lang/sdk/issues/35902
-        final DartType dartType =
-            node.arguments.positional[0].getStaticType(env);
-        final DartType pointerType = node.receiver.getStaticType(env);
-        final DartType nativeType = _pointerTypeGetTypeArg(pointerType);
-
-        // TODO(36730): Allow storing an entire struct to memory.
-        // TODO(36780): Emit a better error message for the struct case.
-        _ensureNativeTypeValid(pointerType, node);
-        _ensureNativeTypeValid(nativeType, node);
-        _ensureNativeTypeSized(nativeType, node, target.name);
-        _ensureNativeTypeToDartType(nativeType, dartType, node);
+        if (nativeType is TypeParameterType) {
+          // Do not rewire generic invocations.
+          return node;
+        }
+        final Class nativeClass = (nativeType as InterfaceType).classNode;
+        final NativeType nt = getType(nativeClass);
+        if (optimizedTypes.contains(nt)) {
+          final typeArguments = [
+            if (nt == NativeType.kPointer) _pointerTypeGetTypeArg(nativeType)
+          ];
+          return StaticInvocation(
+              elementAtMethods[nt],
+              Arguments([node.receiver, node.arguments.positional[0]],
+                  types: typeArguments));
+        }
       }
     } on _FfiStaticTypeError {
       // It's OK to swallow the exception because the diagnostics issued will
@@ -361,9 +349,7 @@
     final DartType shouldBeElementType =
         convertNativeTypeToDartType(containerTypeArg, allowStructs);
     if (elementType == shouldBeElementType) return;
-    // Both subtypes and implicit downcasts are allowed statically.
-    if (env.isSubtypeOf(shouldBeElementType, elementType,
-        SubtypeCheckMode.ignoringNullabilities)) return;
+    // We disable implicit downcasts, they will go away when NNBD lands.
     if (env.isSubtypeOf(elementType, shouldBeElementType,
         SubtypeCheckMode.ignoringNullabilities)) return;
     diagnosticReporter.report(
@@ -393,50 +379,6 @@
     return convertNativeTypeToDartType(nativeType, allowStructs) != null;
   }
 
-  void _ensureNativeTypeSized(
-      DartType nativeType, Expression node, Name targetName) {
-    if (!_nativeTypeSized(nativeType)) {
-      diagnosticReporter.report(
-          templateFfiTypeUnsized.withArguments(targetName.name, nativeType),
-          node.fileOffset,
-          1,
-          node.location.file);
-      throw _FfiStaticTypeError();
-    }
-  }
-
-  /// Unsized NativeTypes do not support [sizeOf] because their size is unknown.
-  /// Consequently, [allocate], [Pointer.load], [Pointer.store], and
-  /// [Pointer.elementAt] are not available.
-  bool _nativeTypeSized(DartType nativeType) {
-    if (nativeType is! InterfaceType) {
-      return false;
-    }
-    final Class nativeClass = (nativeType as InterfaceType).classNode;
-    if (env.isSubtypeOf(InterfaceType(nativeClass), InterfaceType(pointerClass),
-        SubtypeCheckMode.ignoringNullabilities)) {
-      return true;
-    }
-    if (hierarchy.isSubclassOf(nativeClass, structClass)) {
-      return true;
-    }
-    final NativeType nativeType_ = getType(nativeClass);
-    if (nativeType_ == null) {
-      return false;
-    }
-    if (kNativeTypeIntStart.index <= nativeType_.index &&
-        nativeType_.index <= kNativeTypeIntEnd.index) {
-      return true;
-    }
-    if (nativeType_ == NativeType.kFloat || nativeType_ == NativeType.kDouble) {
-      return true;
-    }
-    if (nativeType_ == NativeType.kPointer) {
-      return true;
-    }
-    return false;
-  }
-
   void _ensureIsStaticFunction(Expression node) {
     if ((node is StaticGet && node.target is Procedure) ||
         (node is ConstantExpression && node.constant is TearOffConstant)) {
diff --git a/pkg/vm/testcases/bytecode/async.dart.expect b/pkg/vm/testcases/bytecode/async.dart.expect
index e79ab6e..cce1c2d 100644
--- a/pkg/vm/testcases/bytecode/async.dart.expect
+++ b/pkg/vm/testcases/bytecode/async.dart.expect
@@ -63,17 +63,15 @@
   [26] = Reserved
   [27] = InstanceField dart:core::_Closure::_function (field)
   [28] = Reserved
-  [29] = DirectCall 'dart:async::_asyncStackTraceHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [29] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [30] = Reserved
-  [31] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [31] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [32] = Reserved
-  [33] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [33] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
   [34] = Reserved
-  [35] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+  [35] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
   [36] = Reserved
-  [37] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
-  [38] = Reserved
-  [39] = EndClosureFunctionScope
+  [37] = EndClosureFunctionScope
 }
 Closure #lib::asyncInFieldInitializer (field)::'<anonymous closure>' async (dart:async::Future < dart:core::int > x) -> dart:async::Future < dart:core::Null >
 ClosureCode {
@@ -144,29 +142,27 @@
   Push                 r0
   StoreFieldTOS        CP#1
   StoreContextVar      0, 8
-  Push                 r0
-  LoadContextVar       0, 8
-  DirectCall           CP#29, 1
+  PushNull
   PopLocal             r3
   Push                 r0
   Push                 r0
   LoadContextVar       0, 8
-  DirectCall           CP#31, 1
+  DirectCall           CP#29, 1
   StoreContextVar      0, 3
   Push                 r0
   Push                 r0
   LoadContextVar       0, 8
-  DirectCall           CP#33, 1
+  DirectCall           CP#31, 1
   StoreContextVar      0, 4
   Push                 r0
   LoadContextVar       0, 1
   Push                 r0
   LoadContextVar       0, 8
-  DynamicCall          CP#35, 2
+  DynamicCall          CP#33, 2
   Drop1
   Push                 r0
   LoadContextVar       0, 1
-  InterfaceCall        CP#37, 1
+  InterfaceCall        CP#35, 1
   ReturnTOS
 }
 
@@ -309,23 +305,22 @@
   Push                 r0
   StoreFieldTOS        CP#6
   PopLocal             r6
-  Push                 r6
-  DirectCall           CP#23, 1
+  PushNull
   PopLocal             r3
   Push                 r6
-  DirectCall           CP#25, 1
+  DirectCall           CP#23, 1
   PopLocal             r4
   Push                 r6
-  DirectCall           CP#27, 1
+  DirectCall           CP#25, 1
   PopLocal             r5
   Push                 r0
   LoadContextVar       0, 0
   Push                 r6
-  DynamicCall          CP#29, 2
+  DynamicCall          CP#27, 2
   Drop1
   Push                 r0
   LoadContextVar       0, 0
-  InterfaceCall        CP#31, 1
+  InterfaceCall        CP#29, 1
   ReturnTOS
 }
 ConstantPool {
@@ -352,16 +347,14 @@
   [20] = Reserved
   [21] = InstanceField dart:core::_Closure::_function (field)
   [22] = Reserved
-  [23] = DirectCall 'dart:async::_asyncStackTraceHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [23] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [24] = Reserved
-  [25] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [25] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [26] = Reserved
-  [27] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [27] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
   [28] = Reserved
-  [29] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+  [29] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
   [30] = Reserved
-  [31] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
-  [32] = Reserved
 }
 Closure #lib::foo::':async_op' ([ dynamic :result, dynamic :exception, dynamic :stack_trace ]) -> dynamic
 ClosureCode {
@@ -487,29 +480,27 @@
   Push                 r0
   StoreFieldTOS        CP#6
   StoreContextVar      0, 10
-  Push                 r0
-  LoadContextVar       0, 10
-  DirectCall           CP#27, 1
+  PushNull
   PopLocal             r3
   Push                 r0
   Push                 r0
   LoadContextVar       0, 10
-  DirectCall           CP#29, 1
+  DirectCall           CP#27, 1
   StoreContextVar      0, 4
   Push                 r0
   Push                 r0
   LoadContextVar       0, 10
-  DirectCall           CP#31, 1
+  DirectCall           CP#29, 1
   StoreContextVar      0, 5
   Push                 r0
   LoadContextVar       0, 2
   Push                 r0
   LoadContextVar       0, 10
-  DynamicCall          CP#33, 2
+  DynamicCall          CP#31, 2
   Drop1
   Push                 r0
   LoadContextVar       0, 2
-  InterfaceCall        CP#35, 1
+  InterfaceCall        CP#33, 1
   ReturnTOS
 }
 ConstantPool {
@@ -540,16 +531,14 @@
   [24] = Reserved
   [25] = InstanceField dart:core::_Closure::_function (field)
   [26] = Reserved
-  [27] = DirectCall 'dart:async::_asyncStackTraceHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [27] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [28] = Reserved
-  [29] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [29] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [30] = Reserved
-  [31] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [31] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
   [32] = Reserved
-  [33] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+  [33] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
   [34] = Reserved
-  [35] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
-  [36] = Reserved
 }
 Closure #lib::simpleAsyncAwait::':async_op' ([ dynamic :result, dynamic :exception, dynamic :stack_trace ]) -> dynamic
 ClosureCode {
@@ -742,29 +731,27 @@
   Push                 r0
   StoreFieldTOS        CP#6
   StoreContextVar      0, 10
-  Push                 r0
-  LoadContextVar       0, 10
-  DirectCall           CP#35, 1
+  PushNull
   PopLocal             r3
   Push                 r0
   Push                 r0
   LoadContextVar       0, 10
-  DirectCall           CP#37, 1
+  DirectCall           CP#35, 1
   StoreContextVar      0, 3
   Push                 r0
   Push                 r0
   LoadContextVar       0, 10
-  DirectCall           CP#39, 1
+  DirectCall           CP#37, 1
   StoreContextVar      0, 4
   Push                 r0
   LoadContextVar       0, 1
   Push                 r0
   LoadContextVar       0, 10
-  DynamicCall          CP#41, 2
+  DynamicCall          CP#39, 2
   Drop1
   Push                 r0
   LoadContextVar       0, 1
-  InterfaceCall        CP#43, 1
+  InterfaceCall        CP#41, 1
   ReturnTOS
 }
 ConstantPool {
@@ -803,16 +790,14 @@
   [32] = Reserved
   [33] = InstanceField dart:core::_Closure::_function (field)
   [34] = Reserved
-  [35] = DirectCall 'dart:async::_asyncStackTraceHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [35] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [36] = Reserved
-  [37] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [37] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [38] = Reserved
-  [39] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [39] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
   [40] = Reserved
-  [41] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+  [41] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
   [42] = Reserved
-  [43] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
-  [44] = Reserved
 }
 Closure #lib::loops::':async_op' ([ dynamic :result, dynamic :exception, dynamic :stack_trace ]) -> dynamic
 ClosureCode {
@@ -1142,29 +1127,27 @@
   Push                 r0
   StoreFieldTOS        CP#6
   StoreContextVar      0, 17
-  Push                 r0
-  LoadContextVar       0, 17
-  DirectCall           CP#33, 1
+  PushNull
   PopLocal             r3
   Push                 r0
   Push                 r0
   LoadContextVar       0, 17
-  DirectCall           CP#35, 1
+  DirectCall           CP#33, 1
   StoreContextVar      0, 5
   Push                 r0
   Push                 r0
   LoadContextVar       0, 17
-  DirectCall           CP#37, 1
+  DirectCall           CP#35, 1
   StoreContextVar      0, 6
   Push                 r0
   LoadContextVar       0, 3
   Push                 r0
   LoadContextVar       0, 17
-  DynamicCall          CP#39, 2
+  DynamicCall          CP#37, 2
   Drop1
   Push                 r0
   LoadContextVar       0, 3
-  InterfaceCall        CP#41, 1
+  InterfaceCall        CP#39, 1
   ReturnTOS
 }
 ConstantPool {
@@ -1201,16 +1184,14 @@
   [30] = Reserved
   [31] = InstanceField dart:core::_Closure::_function (field)
   [32] = Reserved
-  [33] = DirectCall 'dart:async::_asyncStackTraceHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [33] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [34] = Reserved
-  [35] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [35] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [36] = Reserved
-  [37] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [37] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
   [38] = Reserved
-  [39] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+  [39] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
   [40] = Reserved
-  [41] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
-  [42] = Reserved
 }
 Closure #lib::tryCatchRethrow::':async_op' ([ dynamic :result, dynamic :exception, dynamic :stack_trace ]) -> dynamic
 ClosureCode {
@@ -1698,17 +1679,15 @@
   [26] = Reserved
   [27] = InstanceField dart:core::_Closure::_function (field)
   [28] = Reserved
-  [29] = DirectCall 'dart:async::_asyncStackTraceHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [29] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [30] = Reserved
-  [31] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [31] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [32] = Reserved
-  [33] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [33] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
   [34] = Reserved
-  [35] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+  [35] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
   [36] = Reserved
-  [37] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
-  [38] = Reserved
-  [39] = EndClosureFunctionScope
+  [37] = EndClosureFunctionScope
 }
 Closure #lib::closure::'nested' async () -> dart:async::Future < dart:core::int >
 ClosureCode {
@@ -1774,29 +1753,27 @@
   Push                 r0
   StoreFieldTOS        CP#1
   StoreContextVar      1, 8
-  Push                 r0
-  LoadContextVar       1, 8
-  DirectCall           CP#29, 1
+  PushNull
   PopLocal             r3
   Push                 r0
   Push                 r0
   LoadContextVar       1, 8
-  DirectCall           CP#31, 1
+  DirectCall           CP#29, 1
   StoreContextVar      1, 2
   Push                 r0
   Push                 r0
   LoadContextVar       1, 8
-  DirectCall           CP#33, 1
+  DirectCall           CP#31, 1
   StoreContextVar      1, 3
   Push                 r0
   LoadContextVar       1, 0
   Push                 r0
   LoadContextVar       1, 8
-  DynamicCall          CP#35, 2
+  DynamicCall          CP#33, 2
   Drop1
   Push                 r0
   LoadContextVar       1, 0
-  InterfaceCall        CP#37, 1
+  InterfaceCall        CP#35, 1
   ReturnTOS
 }
 
@@ -2018,29 +1995,27 @@
   Push                 r0
   StoreFieldTOS        CP#6
   StoreContextVar      0, 8
-  Push                 r0
-  LoadContextVar       0, 8
-  DirectCall           CP#29, 1
+  PushNull
   PopLocal             r3
   Push                 r0
   Push                 r0
   LoadContextVar       0, 8
-  DirectCall           CP#31, 1
+  DirectCall           CP#29, 1
   StoreContextVar      0, 3
   Push                 r0
   Push                 r0
   LoadContextVar       0, 8
-  DirectCall           CP#33, 1
+  DirectCall           CP#31, 1
   StoreContextVar      0, 4
   Push                 r0
   LoadContextVar       0, 1
   Push                 r0
   LoadContextVar       0, 8
-  DynamicCall          CP#35, 2
+  DynamicCall          CP#33, 2
   Drop1
   Push                 r0
   LoadContextVar       0, 1
-  InterfaceCall        CP#37, 1
+  InterfaceCall        CP#35, 1
   ReturnTOS
 }
 ConstantPool {
@@ -2073,16 +2048,14 @@
   [26] = Reserved
   [27] = InstanceField dart:core::_Closure::_function (field)
   [28] = Reserved
-  [29] = DirectCall 'dart:async::_asyncStackTraceHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [29] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [30] = Reserved
-  [31] = DirectCall 'dart:async::_asyncThenWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [31] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
   [32] = Reserved
-  [33] = DirectCall 'dart:async::_asyncErrorWrapperHelper', ArgDesc num-args 1, num-type-args 0, names []
+  [33] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
   [34] = Reserved
-  [35] = DynamicCall 'start', ArgDesc num-args 2, num-type-args 0, names []
+  [35] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
   [36] = Reserved
-  [37] = InterfaceCall 'dart:async::Completer::get:future', ArgDesc num-args 1, num-type-args 0, names []
-  [38] = Reserved
 }
 Closure #lib::testAssert::':async_op' ([ dynamic :result, dynamic :exception, dynamic :stack_trace ]) -> dynamic
 ClosureCode {
diff --git a/pkg/vm/testcases/bytecode/bootstrapping.dart.expect b/pkg/vm/testcases/bytecode/bootstrapping.dart.expect
index a5a1c78..0bd9929 100644
--- a/pkg/vm/testcases/bytecode/bootstrapping.dart.expect
+++ b/pkg/vm/testcases/bytecode/bootstrapping.dart.expect
@@ -133,30 +133,17 @@
   PushConstant         CP#4
   InterfaceCall        CP#2, 2
   AssertBoolean        0
-  PopLocal             r1
-  Jump                 L2
-L1:
-  PushTrue
-  PopLocal             r1
-L2:
-  Push                 r1
-  JumpIfTrue           L3
+  JumpIfTrue           L1
   LoadStatic           CP#0
   PushConstant         CP#5
   InterfaceCall        CP#2, 2
   AssertBoolean        0
-  PopLocal             r0
-  Jump                 L4
-L3:
-  PushTrue
-  PopLocal             r0
-L4:
-  Push                 r0
-  JumpIfFalse          L5
+  JumpIfFalse          L2
+L1:
   LoadStatic           CP#0
   DirectCall           CP#6, 1
   ReturnTOS
-L5:
+L2:
   DirectCall           CP#8, 0
   PushNull
   LoadStatic           CP#0
@@ -583,20 +570,11 @@
   LoadStatic           CP#0
   JumpIfNotNull        L1
   LoadStatic           CP#1
-  EqualsNull
-  BooleanNegateTOS
-  PopLocal             r0
-  Jump                 L2
-L1:
-  PushFalse
-  PopLocal             r0
-L2:
-  Push                 r0
-  JumpIfFalse          L3
+  JumpIfNull           L1
   LoadStatic           CP#1
   DynamicCall          CP#2, 1
   StoreStaticTOS       CP#0
-L3:
+L1:
   LoadStatic           CP#0
   ReturnTOS
 }
diff --git a/pkg/vm/testcases/bytecode/closures.dart b/pkg/vm/testcases/bytecode/closures.dart
index e96872c..669a8f2 100644
--- a/pkg/vm/testcases/bytecode/closures.dart
+++ b/pkg/vm/testcases/bytecode/closures.dart
@@ -153,4 +153,16 @@
   }
 }
 
+abstract class E {
+  int Function(int x, int y) foo1;
+  int Function<T>(T x, T y) get foo2;
+  int evalArg1();
+  int evalArg2();
+  E getE();
+
+  int testCallThroughGetter1() => foo1(evalArg1(), evalArg2());
+  int testCallThroughGetter2() => foo2<int>(evalArg1(), evalArg2());
+  int testCallThroughGetter3() => getE().foo2<int>(evalArg1(), evalArg2());
+}
+
 main() {}
diff --git a/pkg/vm/testcases/bytecode/closures.dart.expect b/pkg/vm/testcases/bytecode/closures.dart.expect
index 3b9cc78..52e029f 100644
--- a/pkg/vm/testcases/bytecode/closures.dart.expect
+++ b/pkg/vm/testcases/bytecode/closures.dart.expect
@@ -1604,6 +1604,162 @@
   ReturnTOS
 }
 
+Class 'E', script = '#lib', abstract
+    extends dart:core::Object
+
+Field 'foo1', type = FunctionType (dart:core::int, dart:core::int) -> dart:core::int, getter = 'get:foo1', setter = 'set:foo1', reflectable
+    value = null
+
+Function '', constructor, reflectable
+    parameters [] (required: 0)
+    return-type #lib::E
+
+Bytecode {
+  Entry                0
+  CheckStack           0
+  Push                 FP[-5]
+  DirectCall           CP#0, 1
+  Drop1
+  PushNull
+  ReturnTOS
+}
+Nullable fields: [#lib::E::foo1 (field)]
+ConstantPool {
+  [0] = DirectCall 'dart:core::Object:: (constructor)', ArgDesc num-args 1, num-type-args 0, names []
+  [1] = Reserved
+}
+
+
+Function 'get:foo2', getter, abstract, reflectable, debuggable
+    parameters [] (required: 0)
+    return-type FunctionType <dart:core::Object T> (null::TypeParam/0, null::TypeParam/0) -> dart:core::int
+
+Function 'evalArg1', abstract, reflectable, debuggable
+    parameters [] (required: 0)
+    return-type dart:core::int
+
+Function 'evalArg2', abstract, reflectable, debuggable
+    parameters [] (required: 0)
+    return-type dart:core::int
+
+Function 'getE', abstract, reflectable, debuggable
+    parameters [] (required: 0)
+    return-type #lib::E
+
+Function 'testCallThroughGetter1', reflectable, debuggable
+    parameters [] (required: 0)
+    return-type dart:core::int
+
+Bytecode {
+  Entry                3
+  CheckStack           0
+  Push                 FP[-5]
+  StoreLocal           r0
+  Push                 FP[-5]
+  InterfaceCall        CP#0, 1
+  PopLocal             r1
+  Push                 FP[-5]
+  InterfaceCall        CP#2, 1
+  PopLocal             r2
+  Push                 r0
+  CheckReceiverForNull CP#4
+  InterfaceCall        CP#5, 1
+  Push                 r1
+  Push                 r2
+  DynamicCall          CP#7, 3
+  ReturnTOS
+}
+ConstantPool {
+  [0] = InterfaceCall '#lib::E::evalArg1', ArgDesc num-args 1, num-type-args 0, names []
+  [1] = Reserved
+  [2] = InterfaceCall '#lib::E::evalArg2', ArgDesc num-args 1, num-type-args 0, names []
+  [3] = Reserved
+  [4] = ObjectRef 'foo1'
+  [5] = InterfaceCall '#lib::E::get:foo1', ArgDesc num-args 1, num-type-args 0, names []
+  [6] = Reserved
+  [7] = DynamicCall 'call', ArgDesc num-args 3, num-type-args 0, names []
+  [8] = Reserved
+}
+
+
+Function 'testCallThroughGetter2', reflectable, debuggable
+    parameters [] (required: 0)
+    return-type dart:core::int
+
+Bytecode {
+  Entry                3
+  CheckStack           0
+  PushConstant         CP#0
+  Push                 FP[-5]
+  StoreLocal           r0
+  Push                 FP[-5]
+  InterfaceCall        CP#1, 1
+  PopLocal             r1
+  Push                 FP[-5]
+  InterfaceCall        CP#3, 1
+  PopLocal             r2
+  Push                 r0
+  CheckReceiverForNull CP#5
+  InterfaceCall        CP#6, 1
+  Push                 r1
+  Push                 r2
+  DynamicCall          CP#8, 4
+  ReturnTOS
+}
+ConstantPool {
+  [0] = ObjectRef < dart:core::int >
+  [1] = InterfaceCall '#lib::E::evalArg1', ArgDesc num-args 1, num-type-args 0, names []
+  [2] = Reserved
+  [3] = InterfaceCall '#lib::E::evalArg2', ArgDesc num-args 1, num-type-args 0, names []
+  [4] = Reserved
+  [5] = ObjectRef 'foo2'
+  [6] = InterfaceCall '#lib::E::get:foo2', ArgDesc num-args 1, num-type-args 0, names []
+  [7] = Reserved
+  [8] = DynamicCall 'call', ArgDesc num-args 3, num-type-args 1, names []
+  [9] = Reserved
+}
+
+
+Function 'testCallThroughGetter3', reflectable, debuggable
+    parameters [] (required: 0)
+    return-type dart:core::int
+
+Bytecode {
+  Entry                3
+  CheckStack           0
+  PushConstant         CP#0
+  Push                 FP[-5]
+  InterfaceCall        CP#1, 1
+  StoreLocal           r0
+  Push                 FP[-5]
+  InterfaceCall        CP#3, 1
+  PopLocal             r1
+  Push                 FP[-5]
+  InterfaceCall        CP#5, 1
+  PopLocal             r2
+  Push                 r0
+  CheckReceiverForNull CP#7
+  InterfaceCall        CP#8, 1
+  Push                 r1
+  Push                 r2
+  DynamicCall          CP#10, 4
+  ReturnTOS
+}
+ConstantPool {
+  [0] = ObjectRef < dart:core::int >
+  [1] = InterfaceCall '#lib::E::getE', ArgDesc num-args 1, num-type-args 0, names []
+  [2] = Reserved
+  [3] = InterfaceCall '#lib::E::evalArg1', ArgDesc num-args 1, num-type-args 0, names []
+  [4] = Reserved
+  [5] = InterfaceCall '#lib::E::evalArg2', ArgDesc num-args 1, num-type-args 0, names []
+  [6] = Reserved
+  [7] = ObjectRef 'foo2'
+  [8] = InterfaceCall '#lib::E::get:foo2', ArgDesc num-args 1, num-type-args 0, names []
+  [9] = Reserved
+  [10] = DynamicCall 'call', ArgDesc num-args 3, num-type-args 1, names []
+  [11] = Reserved
+}
+
 
 }
 ]library #lib from "#lib" as #lib {
@@ -1747,6 +1903,22 @@
       };
     }
   }
+  abstract class E extends dart.core::Object {
+    field (dart.core::int*, dart.core::int*) →* dart.core::int* foo1 = null;
+    synthetic constructor •() → #lib::E*
+      : super dart.core::Object::•()
+      ;
+    abstract get foo2() → <T extends dart.core::Object* = dynamic>(T*, T*) →* dart.core::int*;
+    abstract method evalArg1() → dart.core::int*;
+    abstract method evalArg2() → dart.core::int*;
+    abstract method getE() → #lib::E*;
+    method testCallThroughGetter1() → dart.core::int*
+      return this.{#lib::E::foo1}(this.{#lib::E::evalArg1}(), this.{#lib::E::evalArg2}());
+    method testCallThroughGetter2() → dart.core::int*
+      return this.{#lib::E::foo2}<dart.core::int*>(this.{#lib::E::evalArg1}(), this.{#lib::E::evalArg2}());
+    method testCallThroughGetter3() → dart.core::int*
+      return this.{#lib::E::getE}().{#lib::E::foo2}<dart.core::int*>(this.{#lib::E::evalArg1}(), this.{#lib::E::evalArg2}());
+  }
   static method simpleClosure() → dart.core::int* {
     dart.core::int* x = 5;
     (dart.core::int*) →* dart.core::Null? inc = (dart.core::int* y) → dart.core::Null? {
diff --git a/pkg/vm/testcases/bytecode/field_initializers.dart.expect b/pkg/vm/testcases/bytecode/field_initializers.dart.expect
index c9e7225..0f6d5a0 100644
--- a/pkg/vm/testcases/bytecode/field_initializers.dart.expect
+++ b/pkg/vm/testcases/bytecode/field_initializers.dart.expect
@@ -51,15 +51,14 @@
   Push                 FP[-6]
   PushInt              42
   StoreFieldTOS        CP#0
-  Push                 FP[-6]
   PushInt              43
-  StoreFieldTOS        CP#2
+  Drop1
   Push                 FP[-6]
   Push                 FP[-5]
-  StoreFieldTOS        CP#4
+  StoreFieldTOS        CP#2
   Push                 FP[-6]
   PushInt              44
-  StoreFieldTOS        CP#2
+  StoreFieldTOS        CP#4
   Push                 FP[-6]
   DirectCall           CP#6, 1
   Drop1
@@ -70,9 +69,9 @@
 ConstantPool {
   [0] = InstanceField #lib::A::foo3 (field)
   [1] = Reserved
-  [2] = InstanceField #lib::A::foo5 (field)
+  [2] = InstanceField #lib::A::foo4 (field)
   [3] = Reserved
-  [4] = InstanceField #lib::A::foo4 (field)
+  [4] = InstanceField #lib::A::foo5 (field)
   [5] = Reserved
   [6] = DirectCall 'dart:core::Object:: (constructor)', ArgDesc num-args 1, num-type-args 0, names []
   [7] = Reserved
@@ -89,17 +88,16 @@
   Push                 FP[-7]
   PushInt              42
   StoreFieldTOS        CP#0
-  Push                 FP[-7]
   PushInt              43
-  StoreFieldTOS        CP#2
+  Drop1
   Push                 FP[-7]
   Push                 FP[-6]
-  StoreFieldTOS        CP#4
+  StoreFieldTOS        CP#2
   Push                 FP[-7]
   Push                 FP[-5]
   PushInt              1
   AddInt
-  StoreFieldTOS        CP#2
+  StoreFieldTOS        CP#4
   Push                 FP[-7]
   DirectCall           CP#6, 1
   Drop1
@@ -110,9 +108,9 @@
 ConstantPool {
   [0] = InstanceField #lib::A::foo3 (field)
   [1] = Reserved
-  [2] = InstanceField #lib::A::foo5 (field)
+  [2] = InstanceField #lib::A::foo1 (field)
   [3] = Reserved
-  [4] = InstanceField #lib::A::foo1 (field)
+  [4] = InstanceField #lib::A::foo5 (field)
   [5] = Reserved
   [6] = DirectCall 'dart:core::Object:: (constructor)', ArgDesc num-args 1, num-type-args 0, names []
   [7] = Reserved
@@ -205,9 +203,8 @@
 Bytecode {
   Entry                0
   CheckStack           0
-  Push                 FP[-7]
   PushInt              46
-  StoreFieldTOS        CP#0
+  Drop1
   Push                 FP[-7]
   PushInt              50
   StoreFieldTOS        CP#0
diff --git a/pkg/vm/testcases/bytecode/switch.dart.expect b/pkg/vm/testcases/bytecode/switch.dart.expect
index 98e4d7f..9ce3651 100644
--- a/pkg/vm/testcases/bytecode/switch.dart.expect
+++ b/pkg/vm/testcases/bytecode/switch.dart.expect
@@ -21,16 +21,16 @@
   PopLocal             r0
   Push                 FP[-5]
   PopLocal             r1
-  Push                 r1
   PushInt              1
+  Push                 r1
   InterfaceCall        CP#0, 2
   JumpIfTrue           L1
-  Push                 r1
   PushInt              2
+  Push                 r1
   InterfaceCall        CP#0, 2
   JumpIfTrue           L2
-  Push                 r1
   PushInt              3
+  Push                 r1
   InterfaceCall        CP#0, 2
   JumpIfTrue           L3
   Jump                 L4
@@ -67,28 +67,28 @@
   PopLocal             r0
   Push                 FP[-5]
   PopLocal             r1
-  Push                 r1
   PushInt              1
+  Push                 r1
   InterfaceCall        CP#0, 2
   JumpIfTrue           L1
-  Push                 r1
   PushInt              2
+  Push                 r1
   InterfaceCall        CP#0, 2
   JumpIfTrue           L1
-  Push                 r1
   PushInt              3
+  Push                 r1
   InterfaceCall        CP#0, 2
   JumpIfTrue           L1
-  Push                 r1
   PushInt              4
+  Push                 r1
   InterfaceCall        CP#0, 2
   JumpIfTrue           L2
-  Push                 r1
   PushInt              5
+  Push                 r1
   InterfaceCall        CP#0, 2
   JumpIfTrue           L2
-  Push                 r1
   PushInt              6
+  Push                 r1
   InterfaceCall        CP#0, 2
   JumpIfTrue           L2
   Jump                 L3
@@ -124,28 +124,28 @@
   PopLocal             r0
   Push                 FP[-5]
   PopLocal             r1
-  Push                 r1
   PushInt              1
+  Push                 r1
   InterfaceCall        CP#0, 2
   JumpIfTrue           L1
-  Push                 r1
   PushInt              2
+  Push                 r1
   InterfaceCall        CP#0, 2
   JumpIfTrue           L1
-  Push                 r1
   PushInt              3
+  Push                 r1
   InterfaceCall        CP#0, 2
   JumpIfTrue           L1
-  Push                 r1
   PushInt              4
+  Push                 r1
   InterfaceCall        CP#0, 2
   JumpIfTrue           L2
-  Push                 r1
   PushInt              5
+  Push                 r1
   InterfaceCall        CP#0, 2
   JumpIfTrue           L2
-  Push                 r1
   PushInt              6
+  Push                 r1
   InterfaceCall        CP#0, 2
   JumpIfTrue           L2
   Jump                 L3
diff --git a/pkg/vm/testcases/bytecode/try_blocks.dart.expect b/pkg/vm/testcases/bytecode/try_blocks.dart.expect
index da56542..19e856e 100644
--- a/pkg/vm/testcases/bytecode/try_blocks.dart.expect
+++ b/pkg/vm/testcases/bytecode/try_blocks.dart.expect
@@ -603,12 +603,12 @@
   Push                 r0
   LoadContextVar       0, 0
   PopLocal             r2
-  Push                 r2
   PushInt              1
+  Push                 r2
   InterfaceCall        CP#0, 2
   JumpIfTrue           L1
-  Push                 r2
   PushInt              2
+  Push                 r2
   InterfaceCall        CP#0, 2
   JumpIfTrue           L2
   Jump                 L3
diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn
index 56eb2f6..6751886 100644
--- a/runtime/BUILD.gn
+++ b/runtime/BUILD.gn
@@ -183,19 +183,6 @@
       cflags += [ "-O3" ]
     }
 
-    if (defined(is_asan) && is_asan) {
-      ldflags += [ "-fsanitize=address" ]
-    }
-    if (defined(is_lsan) && is_lsan) {
-      ldflags += [ "-fsanitize=leak" ]
-    }
-    if (defined(is_msan) && is_msan) {
-      ldflags += [ "-fsanitize=memory" ]
-    }
-    if (defined(is_tsan) && is_tsan) {
-      ldflags += [ "-fsanitize=thread" ]
-    }
-
     if (is_fuchsia) {
       # safe-stack does not work with the interpreter.
       cflags += [ "-fno-sanitize=safe-stack" ]
diff --git a/runtime/bin/eventhandler.h b/runtime/bin/eventhandler.h
index 8132cde..245e83c 100644
--- a/runtime/bin/eventhandler.h
+++ b/runtime/bin/eventhandler.h
@@ -16,8 +16,8 @@
 
 // Flags used to provide information and actions to the eventhandler
 // when sending a message about a file descriptor. These flags should
-// be kept in sync with the constants in socket_impl.dart. For more
-// information see the comments in socket_impl.dart
+// be kept in sync with the constants in socket_patch.dart. For more
+// information see the comments in socket_patch.dart
 enum MessageFlags {
   kInEvent = 0,
   kOutEvent = 1,
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index b497db8..ea04e80 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -749,6 +749,8 @@
       new IsolateGroupData(nullptr, nullptr, nullptr, nullptr, false));
   Dart_Isolate isolate;
   char* error = NULL;
+
+  bool loading_kernel_failed = false;
   if (isolate_snapshot_data == NULL) {
     // We need to capture the vmservice library in the core snapshot, so load it
     // in the main isolate as well.
@@ -756,6 +758,7 @@
     isolate = Dart_CreateIsolateGroupFromKernel(
         NULL, NULL, kernel_buffer, kernel_buffer_size, &isolate_flags,
         isolate_group_data.get(), /*isolate_data=*/nullptr, &error);
+    loading_kernel_failed = (isolate == nullptr);
   } else {
     isolate = Dart_CreateIsolateGroup(NULL, NULL, isolate_snapshot_data,
                                       isolate_snapshot_instructions, NULL, NULL,
@@ -766,7 +769,17 @@
     Syslog::PrintErr("%s\n", error);
     free(error);
     free(kernel_buffer);
-    return kErrorExitCode;
+    // The only real reason when `gen_snapshot` fails to create an isolate from
+    // a valid kernel file is if loading the kernel results in a "compile-time"
+    // error.
+    //
+    // There are other possible reasons, like memory allocation failures, but
+    // those are very uncommon.
+    //
+    // The Dart API doesn't allow us to distinguish the different error cases,
+    // so we'll use [kCompilationErrorExitCode] for failed kernel loading, since
+    // a compile-time error is the most probable cause.
+    return loading_kernel_failed ? kCompilationErrorExitCode : kErrorExitCode;
   }
 
   Dart_EnterScope();
diff --git a/runtime/bin/reference_counting.h b/runtime/bin/reference_counting.h
index 436f2ae..caafffa 100644
--- a/runtime/bin/reference_counting.h
+++ b/runtime/bin/reference_counting.h
@@ -5,7 +5,7 @@
 #ifndef RUNTIME_BIN_REFERENCE_COUNTING_H_
 #define RUNTIME_BIN_REFERENCE_COUNTING_H_
 
-#include "platform/atomic.h"
+#include <atomic>
 
 namespace dart {
 namespace bin {
@@ -35,24 +35,24 @@
  public:
   ReferenceCounted() : ref_count_(1) {
 #if defined(DEBUG)
-    AtomicOperations::FetchAndIncrement(&instances_);
+    instances_.fetch_add(1u, std::memory_order_relaxed);
 #endif  // defined(DEBUG)
   }
 
   virtual ~ReferenceCounted() {
     ASSERT(ref_count_ == 0);
 #if defined(DEBUG)
-    AtomicOperations::FetchAndDecrement(&instances_);
+    instances_.fetch_sub(1u, std::memory_order_relaxed);
 #endif  // defined(DEBUG)
   }
 
   void Retain() {
-    intptr_t old = AtomicOperations::FetchAndIncrement(&ref_count_);
+    intptr_t old = ref_count_.fetch_add(1u, std::memory_order_relaxed);
     ASSERT(old > 0);
   }
 
   void Release() {
-    intptr_t old = AtomicOperations::FetchAndDecrement(&ref_count_);
+    intptr_t old = ref_count_.fetch_sub(1u, std::memory_order_acq_rel);
     ASSERT(old > 0);
     if (old == 1) {
       delete static_cast<Derived*>(this);
@@ -60,25 +60,29 @@
   }
 
 #if defined(DEBUG)
-  static intptr_t instances() { return instances_; }
+  static intptr_t instances() {
+    return instances_.load(std::memory_order_relaxed);
+  }
 #endif  // defined(DEBUG)
 
  private:
 #if defined(DEBUG)
-  static intptr_t instances_;
+  static std::atomic<intptr_t> instances_;
 #endif  // defined(DEBUG)
 
-  intptr_t ref_count_;
+  std::atomic<intptr_t> ref_count_;
 
   // These are used only in the ASSERT below in RefCntReleaseScope.
-  intptr_t ref_count() const { return ref_count_; }
+  intptr_t ref_count() const {
+    return ref_count_.load(std::memory_order_relaxed);
+  }
   friend class RefCntReleaseScope<Derived>;
   DISALLOW_COPY_AND_ASSIGN(ReferenceCounted);
 };
 
 #if defined(DEBUG)
 template <class Derived>
-intptr_t ReferenceCounted<Derived>::instances_ = 0;
+std::atomic<intptr_t> ReferenceCounted<Derived>::instances_ = {0};
 #endif
 
 // Creates a scope at the end of which a reference counted object is
diff --git a/runtime/lib/ffi.cc b/runtime/lib/ffi.cc
index f103f2e..eb1ee94 100644
--- a/runtime/lib/ffi.cc
+++ b/runtime/lib/ffi.cc
@@ -48,116 +48,8 @@
   }
 }
 
-enum class FfiVariance { kCovariant = 0, kContravariant = 1 };
-
-// Checks that a dart type correspond to a [NativeType].
-// Because this is checked already in a kernel transformation, it does not throw
-// an ArgumentException but a boolean which should be asserted.
-//
-// [Int8]                               -> [int]
-// [Int16]                              -> [int]
-// [Int32]                              -> [int]
-// [Int64]                              -> [int]
-// [Uint8]                              -> [int]
-// [Uint16]                             -> [int]
-// [Uint32]                             -> [int]
-// [Uint64]                             -> [int]
-// [IntPtr]                             -> [int]
-// [Double]                             -> [double]
-// [Float]                              -> [double]
-// [Pointer]<T>                         -> [Pointer]<T>
-// T extends [Struct]                   -> T
-// [NativeFunction]<T1 Function(T2, T3) -> S1 Function(S2, S3)
-//    where DartRepresentationOf(Tn) -> Sn
-static bool DartAndCTypeCorrespond(const AbstractType& native_type,
-                                   const AbstractType& dart_type,
-                                   FfiVariance variance) {
-  classid_t native_type_cid = native_type.type_class_id();
-  if (RawObject::IsFfiTypeIntClassId(native_type_cid)) {
-    return dart_type.IsSubtypeOf(AbstractType::Handle(Type::IntType()),
-                                 Heap::kNew);
-  }
-  if (RawObject::IsFfiTypeDoubleClassId(native_type_cid)) {
-    return dart_type.IsSubtypeOf(AbstractType::Handle(Type::Double()),
-                                 Heap::kNew);
-  }
-  if (RawObject::IsFfiPointerClassId(native_type_cid)) {
-    return (variance == FfiVariance::kCovariant &&
-            dart_type.IsSubtypeOf(native_type, Heap::kNew)) ||
-           (variance == FfiVariance::kContravariant &&
-            native_type.IsSubtypeOf(dart_type, Heap::kNew)) ||
-           dart_type.IsNullType();
-  }
-  if (RawObject::IsFfiTypeNativeFunctionClassId(native_type_cid)) {
-    if (!dart_type.IsFunctionType()) {
-      return false;
-    }
-    TypeArguments& nativefunction_type_args =
-        TypeArguments::Handle(native_type.arguments());
-    AbstractType& nativefunction_type_arg =
-        AbstractType::Handle(nativefunction_type_args.TypeAt(0));
-    if (!nativefunction_type_arg.IsFunctionType()) {
-      return false;
-    }
-    Function& dart_function =
-        Function::Handle((Type::Cast(dart_type)).signature());
-    if (dart_function.NumTypeParameters() != 0 ||
-        dart_function.HasOptionalPositionalParameters() ||
-        dart_function.HasOptionalNamedParameters()) {
-      return false;
-    }
-    Function& nativefunction_function =
-        Function::Handle(((Type&)nativefunction_type_arg).signature());
-    if (nativefunction_function.NumTypeParameters() != 0 ||
-        nativefunction_function.HasOptionalPositionalParameters() ||
-        nativefunction_function.HasOptionalNamedParameters()) {
-      return false;
-    }
-    if (!(dart_function.NumParameters() ==
-          nativefunction_function.NumParameters())) {
-      return false;
-    }
-    if (!DartAndCTypeCorrespond(
-            AbstractType::Handle(nativefunction_function.result_type()),
-            AbstractType::Handle(dart_function.result_type()), variance)) {
-      return false;
-    }
-    for (intptr_t i = 0; i < dart_function.NumParameters(); i++) {
-      if (!DartAndCTypeCorrespond(
-              AbstractType::Handle(nativefunction_function.ParameterTypeAt(i)),
-              AbstractType::Handle(dart_function.ParameterTypeAt(i)),
-              variance)) {
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-static void CheckDartAndCTypeCorrespond(const AbstractType& native_type,
-                                        const AbstractType& dart_type,
-                                        FfiVariance variance) {
-  if (!DartAndCTypeCorrespond(native_type, dart_type, variance)) {
-    const String& error = String::Handle(String::NewFormatted(
-        "Expected type '%s' to be different, it should be "
-        "DartRepresentationOf('%s').",
-        String::Handle(dart_type.UserVisibleName()).ToCString(),
-        String::Handle(native_type.UserVisibleName()).ToCString()));
-    Exceptions::ThrowArgumentError(error);
-  }
-}
-
 // The following functions are runtime checks on arguments.
 
-static const Pointer& AsPointer(const Instance& instance) {
-  if (!instance.IsPointer()) {
-    const String& error = String::Handle(String::NewFormatted(
-        "Expected a Pointer object but found %s", instance.ToCString()));
-    Exceptions::ThrowArgumentError(error);
-  }
-  return Pointer::Cast(instance);
-}
-
 static const Integer& AsInteger(const Instance& instance) {
   if (!instance.IsInteger()) {
     const String& error = String::Handle(String::NewFormatted(
@@ -196,78 +88,25 @@
 
 // The remainder of this file implements the dart:ffi native methods.
 
-DEFINE_NATIVE_ENTRY(Ffi_allocate, 1, 1) {
-  GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0));
-
-  CheckSized(type_arg);
-  size_t element_size = SizeOf(type_arg);
-
-  GET_NON_NULL_NATIVE_ARGUMENT(Integer, argCount, arguments->NativeArgAt(0));
-  int64_t count = argCount.AsInt64Value();
-  size_t size = element_size * count;  // Truncates overflow.
-  size_t memory = reinterpret_cast<size_t>(malloc(size));
-  if (memory == 0) {
-    const String& error = String::Handle(String::NewFormatted(
-        "allocating (%" Pd ") bytes of memory failed", size));
-    Exceptions::ThrowArgumentError(error);
-  }
-
-  RawPointer* result = Pointer::New(type_arg, memory);
-  return result;
-}
-
 DEFINE_NATIVE_ENTRY(Ffi_fromAddress, 1, 1) {
   GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0));
   GET_NON_NULL_NATIVE_ARGUMENT(Integer, arg_ptr, arguments->NativeArgAt(0));
   return Pointer::New(type_arg, arg_ptr.AsInt64Value());
 }
 
-DEFINE_NATIVE_ENTRY(Ffi_elementAt, 0, 2) {
-  GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
-  GET_NON_NULL_NATIVE_ARGUMENT(Integer, index, arguments->NativeArgAt(1));
-  AbstractType& pointer_type_arg =
-      AbstractType::Handle(zone, pointer.type_argument());
-  CheckSized(pointer_type_arg);
-  return Pointer::New(pointer_type_arg,
-                      pointer.NativeAddress() +
-                          index.AsInt64Value() * SizeOf(pointer_type_arg));
-}
-
-DEFINE_NATIVE_ENTRY(Ffi_offsetBy, 0, 2) {
-  GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
-  GET_NON_NULL_NATIVE_ARGUMENT(Integer, offset, arguments->NativeArgAt(1));
-  AbstractType& pointer_type_arg =
-      AbstractType::Handle(pointer.type_argument());
-
-  return Pointer::New(pointer_type_arg,
-                      pointer.NativeAddress() + offset.AsInt64Value());
-}
-
-DEFINE_NATIVE_ENTRY(Ffi_cast, 1, 1) {
-  GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
-  GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0));
-  return Pointer::New(type_arg, pointer.NativeAddress());
-}
-
-DEFINE_NATIVE_ENTRY(Ffi_free, 0, 1) {
-  GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
-
-  free(reinterpret_cast<void*>(pointer.NativeAddress()));
-  pointer.SetNativeAddress(0);
-
-  return Object::null();
-}
-
 DEFINE_NATIVE_ENTRY(Ffi_address, 0, 1) {
   GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
   return Integer::New(pointer.NativeAddress());
 }
 
-static RawObject* LoadValue(Zone* zone,
-                            const Pointer& target,
-                            const AbstractType& instance_type_arg) {
-  classid_t type_cid = instance_type_arg.type_class_id();
-  size_t address = target.NativeAddress();
+static RawObject* LoadValueNumeric(Zone* zone,
+                                   const Pointer& target,
+                                   classid_t type_cid,
+                                   const Integer& index) {
+  // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr.
+  const size_t address =
+      target.NativeAddress() + static_cast<intptr_t>(index.AsInt64Value()) *
+                                   compiler::ffi::ElementSizeInBytes(type_cid);
   switch (type_cid) {
     case kFfiInt8Cid:
       return Integer::New(*reinterpret_cast<int8_t*>(address));
@@ -291,61 +130,88 @@
       return Double::New(*reinterpret_cast<float_t*>(address));
     case kFfiDoubleCid:
       return Double::New(*reinterpret_cast<double_t*>(address));
-    default: {
-      if (IsPointerType(instance_type_arg)) {
-        const AbstractType& type_arg = AbstractType::Handle(
-            TypeArguments::Handle(instance_type_arg.arguments())
-                .TypeAt(Pointer::kNativeTypeArgPos));
-        return Pointer::New(type_arg, reinterpret_cast<size_t>(
-                                          *reinterpret_cast<void**>(address)));
-      } else {
-        // Result is a struct class -- find <class name>.#fromPointer
-        // constructor and call it.
-        Class& cls = Class::Handle(zone, instance_type_arg.type_class());
-        const Function& constructor =
-            Function::Handle(cls.LookupFunctionAllowPrivate(String::Handle(
-                String::Concat(String::Handle(String::Concat(
-                                   String::Handle(cls.Name()), Symbols::Dot())),
-                               Symbols::StructFromPointer()))));
-        ASSERT(!constructor.IsNull());
-        ASSERT(constructor.IsGenerativeConstructor());
-        ASSERT(!Object::Handle(constructor.VerifyCallEntryPoint()).IsError());
-        Instance& new_object = Instance::Handle(Instance::New(cls));
-        new_object.SetTypeArguments(
-            TypeArguments::Handle(instance_type_arg.arguments()));
-        ASSERT(cls.is_allocated() ||
-               Dart::vm_snapshot_kind() != Snapshot::kFullAOT);
-        const Array& args = Array::Handle(zone, Array::New(2));
-        args.SetAt(0, new_object);
-        args.SetAt(1, target);
-        Object& constructorResult =
-            Object::Handle(DartEntry::InvokeFunction(constructor, args));
-        ASSERT(!constructorResult.IsError());
-        return new_object.raw();
-      }
-    }
+    default:
+      UNREACHABLE();
   }
 }
 
-DEFINE_NATIVE_ENTRY(Ffi_load, 1, 1) {
-  GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
-  GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0));
-  AbstractType& pointer_type_arg =
-      AbstractType::Handle(pointer.type_argument());
-  CheckSized(pointer_type_arg);
-  CheckDartAndCTypeCorrespond(pointer_type_arg, type_arg,
-                              FfiVariance::kContravariant);
+#define DEFINE_NATIVE_ENTRY_LOAD(type)                                         \
+  DEFINE_NATIVE_ENTRY(Ffi_load##type, 0, 2) {                                  \
+    GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0)); \
+    GET_NON_NULL_NATIVE_ARGUMENT(Integer, index, arguments->NativeArgAt(1));   \
+    return LoadValueNumeric(zone, pointer, kFfi##type##Cid, index);            \
+  }
+CLASS_LIST_FFI_NUMERIC(DEFINE_NATIVE_ENTRY_LOAD)
+#undef DEFINE_NATIVE_ENTRY_LOAD
 
-  return LoadValue(zone, pointer, pointer_type_arg);
+DEFINE_NATIVE_ENTRY(Ffi_loadPointer, 1, 2) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
+  GET_NON_NULL_NATIVE_ARGUMENT(Integer, index, arguments->NativeArgAt(1));
+
+  const auto& pointer_type_arg =
+      AbstractType::Handle(zone, pointer.type_argument());
+  const AbstractType& type_arg =
+      AbstractType::Handle(TypeArguments::Handle(pointer_type_arg.arguments())
+                               .TypeAt(Pointer::kNativeTypeArgPos));
+
+  // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr.
+  const size_t address =
+      pointer.NativeAddress() +
+      static_cast<intptr_t>(index.AsInt64Value()) * SizeOf(pointer_type_arg);
+
+  return Pointer::New(type_arg, *reinterpret_cast<uword*>(address));
 }
 
-static void StoreValue(Zone* zone,
-                       const Pointer& pointer,
-                       classid_t type_cid,
-                       const Instance& new_value) {
-  uint8_t* const address = reinterpret_cast<uint8_t*>(pointer.NativeAddress());
-  AbstractType& pointer_type_arg =
+static RawObject* LoadValueStruct(Zone* zone,
+                                  const Pointer& target,
+                                  const AbstractType& instance_type_arg) {
+  // Result is a struct class -- find <class name>.#fromPointer
+  // constructor and call it.
+  const Class& cls = Class::Handle(zone, instance_type_arg.type_class());
+  const Function& constructor =
+      Function::Handle(cls.LookupFunctionAllowPrivate(String::Handle(
+          String::Concat(String::Handle(String::Concat(
+                             String::Handle(cls.Name()), Symbols::Dot())),
+                         Symbols::StructFromPointer()))));
+  ASSERT(!constructor.IsNull());
+  ASSERT(constructor.IsGenerativeConstructor());
+  ASSERT(!Object::Handle(constructor.VerifyCallEntryPoint()).IsError());
+  const Instance& new_object = Instance::Handle(Instance::New(cls));
+  ASSERT(cls.is_allocated() || Dart::vm_snapshot_kind() != Snapshot::kFullAOT);
+  const Array& args = Array::Handle(zone, Array::New(2));
+  args.SetAt(0, new_object);
+  args.SetAt(1, target);
+  const Object& constructorResult =
+      Object::Handle(DartEntry::InvokeFunction(constructor, args));
+  ASSERT(!constructorResult.IsError());
+  return new_object.raw();
+}
+
+DEFINE_NATIVE_ENTRY(Ffi_loadStruct, 0, 2) {
+  GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
+  const AbstractType& pointer_type_arg =
       AbstractType::Handle(pointer.type_argument());
+  GET_NON_NULL_NATIVE_ARGUMENT(Integer, index, arguments->NativeArgAt(1));
+
+  // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr.
+  const size_t address =
+      pointer.NativeAddress() +
+      static_cast<intptr_t>(index.AsInt64Value()) * SizeOf(pointer_type_arg);
+  const Pointer& pointer_offset =
+      Pointer::Handle(zone, Pointer::New(pointer_type_arg, address));
+
+  return LoadValueStruct(zone, pointer_offset, pointer_type_arg);
+}
+
+static void StoreValueNumeric(Zone* zone,
+                              const Pointer& pointer,
+                              classid_t type_cid,
+                              const Integer& index,
+                              const Instance& new_value) {
+  // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr.
+  const size_t address =
+      pointer.NativeAddress() + static_cast<intptr_t>(index.AsInt64Value()) *
+                                    compiler::ffi::ElementSizeInBytes(type_cid);
   switch (type_cid) {
     case kFfiInt8Cid:
       *reinterpret_cast<int8_t*>(address) = AsInteger(new_value).AsInt64Value();
@@ -388,37 +254,45 @@
     case kFfiDoubleCid:
       *reinterpret_cast<double*>(address) = AsDouble(new_value).value();
       break;
-    case kFfiPointerCid: {
-      ASSERT(IsPointerType(pointer_type_arg));
-      ASSERT(new_value.IsPointer());
-      const void* const stored =
-          reinterpret_cast<void*>(AsPointer(new_value).NativeAddress());
-      *reinterpret_cast<const void**>(address) = stored;
-      break;
-    }
     default:
       UNREACHABLE();
   }
 }
 
-DEFINE_NATIVE_ENTRY(Ffi_store, 0, 2) {
+#define DEFINE_NATIVE_ENTRY_STORE(type)                                        \
+  DEFINE_NATIVE_ENTRY(Ffi_store##type, 0, 3) {                                 \
+    GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0)); \
+    GET_NON_NULL_NATIVE_ARGUMENT(Integer, index, arguments->NativeArgAt(1));   \
+    GET_NON_NULL_NATIVE_ARGUMENT(Instance, value, arguments->NativeArgAt(2));  \
+    StoreValueNumeric(zone, pointer, kFfi##type##Cid, index, value);           \
+    return Object::null();                                                     \
+  }
+CLASS_LIST_FFI_NUMERIC(DEFINE_NATIVE_ENTRY_STORE)
+#undef DEFINE_NATIVE_ENTRY_STORE
+
+DEFINE_NATIVE_ENTRY(Ffi_storePointer, 0, 3) {
   GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
-  GET_NATIVE_ARGUMENT(Instance, new_value, arguments->NativeArgAt(1));
-  AbstractType& arg_type = AbstractType::Handle(new_value.GetType(Heap::kNew));
+  GET_NON_NULL_NATIVE_ARGUMENT(Integer, index, arguments->NativeArgAt(1));
+  GET_NON_NULL_NATIVE_ARGUMENT(Pointer, new_value, arguments->NativeArgAt(2));
   AbstractType& pointer_type_arg =
       AbstractType::Handle(pointer.type_argument());
-  CheckSized(pointer_type_arg);
-  CheckDartAndCTypeCorrespond(pointer_type_arg, arg_type,
-                              FfiVariance::kCovariant);
 
-  if (new_value.IsNull()) {
-    const String& error = String::Handle(
-        String::NewFormatted("Argument to Pointer.store is null."));
+  auto& new_value_type =
+      AbstractType::Handle(zone, new_value.GetType(Heap::kNew));
+  if (!new_value_type.IsSubtypeOf(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(),
+        String::Handle(pointer_type_arg.UserVisibleName()).ToCString()));
     Exceptions::ThrowArgumentError(error);
   }
 
-  classid_t type_cid = pointer_type_arg.type_class_id();
-  StoreValue(zone, pointer, type_cid, new_value);
+  ASSERT(IsPointerType(pointer_type_arg));
+  // TODO(36370): Make representation consistent with kUnboxedFfiIntPtr.
+  const size_t address =
+      pointer.NativeAddress() +
+      static_cast<intptr_t>(index.AsInt64Value()) * SizeOf(pointer_type_arg);
+  *reinterpret_cast<uword*>(address) = new_value.NativeAddress();
   return Object::null();
 }
 
@@ -429,7 +303,6 @@
   return Integer::New(SizeOf(type_arg));
 }
 
-
 // Static invocations to this method are translated directly in streaming FGB
 // and bytecode FGB. However, we can still reach this entrypoint in the bytecode
 // interpreter.
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 846e8ab..b5a8725 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -246,7 +246,7 @@
   args.SetAt(0, MirrorReference::Handle(MirrorReference::New(func)));
 
   String& name = String::Handle(func.name());
-  name = String::ScrubNameRetainPrivate(name);
+  name = String::ScrubNameRetainPrivate(name, func.is_extension_member());
   args.SetAt(1, name);
   args.SetAt(2, owner_mirror);
   args.SetAt(3, instantiator);
@@ -274,6 +274,8 @@
       (static_cast<intptr_t>(func.is_external()) << Mirrors::kExternal);
   bool is_synthetic = func.is_no_such_method_forwarder();
   kind_flags |= (static_cast<intptr_t>(is_synthetic) << Mirrors::kSynthetic);
+  kind_flags |= (static_cast<intptr_t>(func.is_extension_member())
+                 << Mirrors::kExtensionMember);
   args.SetAt(5, Smi::Handle(Smi::New(kind_flags)));
 
   return CreateMirror(Symbols::_MethodMirror(), args);
@@ -286,7 +288,7 @@
 
   const String& name = String::Handle(field.name());
 
-  const Array& args = Array::Handle(Array::New(7));
+  const Array& args = Array::Handle(Array::New(8));
   args.SetAt(0, field_ref);
   args.SetAt(1, name);
   args.SetAt(2, owner_mirror);
@@ -294,6 +296,7 @@
   args.SetAt(4, Bool::Get(field.is_static()));
   args.SetAt(5, Bool::Get(field.is_final()));
   args.SetAt(6, Bool::Get(field.is_const()));
+  args.SetAt(7, Bool::Get(field.is_extension_member()));
 
   return CreateMirror(Symbols::_VariableMirror(), args);
 }
@@ -1320,12 +1323,16 @@
   Function& function = Function::Handle();
   bool callable = closure.IsCallable(&function);
   if (callable) {
-    if (function.IsImplicitClosureFunction()) {
+    const Function& parent = Function::Handle(function.parent_function());
+    if (function.IsImplicitClosureFunction() || parent.is_extension_member()) {
       // The VM uses separate Functions for tear-offs, but the mirrors consider
       // the tear-offs to be the same as the torn-off methods. Avoid handing out
       // a reference to the tear-off here to avoid a special case in the
       // the equality test.
-      function = function.parent_function();
+      // In the case of extension methods also we avoid handing out a reference
+      // to the tear-off and instead get the parent function of the
+      // anonymous closure.
+      function = parent.raw();
     }
 
     Type& instantiator = Type::Handle();
diff --git a/runtime/lib/mirrors.h b/runtime/lib/mirrors.h
index 7a6fe4a..a13de55 100644
--- a/runtime/lib/mirrors.h
+++ b/runtime/lib/mirrors.h
@@ -21,7 +21,8 @@
   V(kRedirectingCtor)                                                          \
   V(kFactoryCtor)                                                              \
   V(kExternal)                                                                 \
-  V(kSynthetic)
+  V(kSynthetic)                                                                \
+  V(kExtensionMember)
 
   // These offsets much be kept in sync with those in mirrors_impl.dart.
   enum KindShifts {
diff --git a/runtime/llvm_codegen/bit/BUILD.gn b/runtime/llvm_codegen/bit/BUILD.gn
index a61ad74..a7365c1 100644
--- a/runtime/llvm_codegen/bit/BUILD.gn
+++ b/runtime/llvm_codegen/bit/BUILD.gn
@@ -7,7 +7,11 @@
     "main.cc",
   ]
   root_dir = rebase_path(root_out_dir)
-  defines = [ "LIT_BINARY_DIR=\"$root_dir\"" ]
+  clang_dir = rebase_path("//buildtools/linux-x64/clang/bin")
+  defines = [
+    "BIT_BINARY_DIR=\"$root_dir\"",
+    "BIT_CLANG_DIR=\"$clang_dir\"",
+  ]
   deps = [
     "../../../third_party/llvm:LLVMSupport",
   ]
@@ -21,11 +25,18 @@
     "test.cc",
   ]
 
+  root_dir = rebase_path(root_out_dir)
+  clang_dir = rebase_path("//buildtools/linux-x64/clang/bin")
+  defines = [
+    "BIT_BINARY_DIR=\"$root_dir\"",
+    "BIT_CLANG_DIR=\"$clang_dir\"",
+  ]
+
   deps = [
     "../../../third_party/llvm:LLVMSupport",
   ]
 
   include_dirs = [ "//runtime" ]
 
-  defines = [ "TESTING" ]
+  defines += [ "TESTING" ]
 }
diff --git a/runtime/llvm_codegen/bit/bit.h b/runtime/llvm_codegen/bit/bit.h
index 19eb5f8..ea57b03 100644
--- a/runtime/llvm_codegen/bit/bit.h
+++ b/runtime/llvm_codegen/bit/bit.h
@@ -31,10 +31,13 @@
   sys::path::append(tmp_file, sys::path::Style::native, config.out_dir,
                     basename + ".tmp");
   SmallString<128> codegen;
-  sys::path::append(codegen, sys::path::Style::native, LIT_BINARY_DIR,
+  sys::path::append(codegen, sys::path::Style::native, BIT_BINARY_DIR,
                     "codegen");
   SmallString<128> bit;
-  sys::path::append(bit, sys::path::Style::native, LIT_BINARY_DIR, "bit");
+  sys::path::append(bit, sys::path::Style::native, BIT_BINARY_DIR, "bit");
+
+  SmallString<128> clang;
+  sys::path::append(clang, sys::path::Style::native, BIT_CLANG_DIR, "clang");
 
   // Set up our substitutions.
   StringMap<std::string> subs;
@@ -42,8 +45,9 @@
   subs["p"] = test_dir.str();
   subs["P"] = test_dir.str();
   subs["t"] = tmp_file.str().str();
-  subs["codegen"] = codegen.str().str();
-  subs["bit"] = bit.str().str();
+  subs["{codegen}"] = codegen.str().str();
+  subs["{bit}"] = bit.str().str();
+  subs["{clang}"] = clang.str().str();
   return subs;
 }
 
diff --git a/runtime/llvm_codegen/codegen/BUILD.gn b/runtime/llvm_codegen/codegen/BUILD.gn
index 3174f26..3addb35 100644
--- a/runtime/llvm_codegen/codegen/BUILD.gn
+++ b/runtime/llvm_codegen/codegen/BUILD.gn
@@ -2,13 +2,44 @@
 # for 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("../../vm/compiler/compiler_sources.gni")
+
+config("config") {
+  include_dirs = [
+    "../../"
+  ]
+
+  cflags = [
+    "-Wno-unused-private-field"
+  ]
+}
+
+_lib_llvm_so = "../../../third_party/llvm/lib/libLLVM-9svn.so"
+
+config("llvm") {
+  include_dirs = [ "../../../third_party/llvm/include" ]
+  libs = [ _lib_llvm_so ]
+}
+
+copy("lib_llvm") {
+  sources = [ _lib_llvm_so ]
+  outputs = [ "$root_out_dir/libLLVM-9svn.so" ]
+  public_configs = [ ":llvm" ]
+}
+
 executable("codegen") {
   sources = [
     "main.cc",
+    "dart.cc",
+    "dart.h"
   ]
 
   deps = [
-    "../../../third_party/llvm:LLVMAsmPrinter",
-    "../../../third_party/llvm:LLVMIRReader",
+    ":lib_llvm",
+    "../..:libdart_nosnapshot_with_precompiler",
+    "../../vm:libdart_vm_nosnapshot_with_precompiler",
+    "../../platform:libdart_platform_nosnapshot_with_precompiler",
   ]
+
+  configs += [ ":config" ]
 }
diff --git a/runtime/llvm_codegen/codegen/dart.cc b/runtime/llvm_codegen/codegen/dart.cc
new file mode 100644
index 0000000..e400b41
--- /dev/null
+++ b/runtime/llvm_codegen/codegen/dart.cc
@@ -0,0 +1,357 @@
+// 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 "dart.h"
+
+#include "llvm/ADT/StringSwitch.h"
+#include "vm/dart_api_state.h"
+
+using namespace llvm;
+
+Value* DartThreadObject::GetOffset(Type* type, intptr_t offset) const {
+  auto& ctx = bb_builder_.Context();
+  auto& builder = bb_builder_.Builder();
+  auto int64ty = IntegerType::getInt64Ty(ctx);
+  // TODO: This is only correct for x86_64. On x86 we need to use 257,
+  // and only arm targets an entirely different mechanism will be
+  // required since there isn't an unused register. On Arm we can
+  // probably still use the thread register as long as we're careful
+  // to set it back on thread boundaries.
+  // On x86_64 fs (257) is used for TLS but gs (256) is unused
+  // On x86 gs (256) is used for TLS but fs (257) is unused
+  // we use the unused segment so as to not conflict with TLS which
+  // allows linking against native code that uses TLS without needing
+  // to handle any kind of context switching.
+  constexpr unsigned kDartThreadPointerAddressSpace = 256;
+  auto* ptr_tls = PointerType::get(type, kDartThreadPointerAddressSpace);
+  auto* offset_value = ConstantInt::get(int64ty, offset);
+  auto* tls_value = builder.CreateIntToPtr(offset_value, ptr_tls);
+  return builder.CreateLoad(tls_value);
+}
+
+Value* DartThreadObject::StackLimit() const {
+  auto& ctx = bb_builder_.Context();
+  return GetOffset(IntegerType::getInt64Ty(ctx), kThreadStackLimitOffset);
+}
+
+Value* BasicBlockBuilder::GetValue(const DartValue* v) {
+  auto iter = values_.find(v);
+  if (iter == values_.end()) {
+    auto* out = v->Make(*this);
+    values_[v] = out;
+    return out;
+  }
+  return iter->second;
+}
+
+DartInstruction::~DartInstruction() {}
+
+static Error CreateError(const Twine& err) {
+  return make_error<StringError>(err, inconvertibleErrorCode());
+}
+
+Value* DartConstant::Make(BasicBlockBuilder& bb_builder) const {
+  auto& ctx = bb_builder.Context();
+  switch (type) {
+    case DartConstant::Type::String:
+      auto constant = ConstantDataArray::getString(ctx, str);
+      auto gv =
+          new GlobalVariable(bb_builder.Module(), constant->getType(), true,
+                             GlobalVariable::ExternalLinkage, constant);
+      return ConstantExpr::getBitCast(gv, GetType(bb_builder));
+  }
+}
+
+Type* DartConstant::GetType(BasicBlockBuilder& bb_builder) const {
+  // TODO: Right now this returns a c-string type but that's not correct.
+  // We should move this to a generic object type (e.g. a tagged pointer).
+  auto& ctx = bb_builder.Context();
+  auto int8ty = IntegerType::getInt8Ty(ctx);
+  return PointerType::get(int8ty, 0);
+}
+
+void InstCheckStackOverflow::Build(BasicBlockBuilder& bb_builder) const {
+  auto& builder = bb_builder.Builder();
+  auto& ctx = bb_builder.Context();
+  auto& module = bb_builder.Module();
+  auto& thread_object = bb_builder.ThreadObject();
+
+  // TODO: This is only correct on 64-bit architectures.
+  auto int64ty = IntegerType::getInt64Ty(ctx);
+
+  // Get the stack pointer.
+  auto spi_type = Intrinsic::getType(ctx, Intrinsic::stacksave);
+  auto spi_func = Intrinsic::getDeclaration(&module, Intrinsic::stacksave);
+  auto sp_raw = builder.CreateCall(spi_type, spi_func);
+  auto sp = builder.CreatePtrToInt(sp_raw, int64ty);
+
+  // Get the stack limit from the thread pointer.
+  auto stack_limit = thread_object.StackLimit();
+
+  // Now compare the stack pointer and limit.
+  auto error_bb = bb_builder.AddBasicBlock();
+  auto cont_bb = bb_builder.AddBasicBlock();
+  auto cmp = builder.CreateICmpULT(sp, stack_limit);
+  builder.CreateCondBr(cmp, error_bb, cont_bb);
+
+  // Now build the error path.
+  // TODO: Don't just trap here. For now we just trap rather than
+  // handling the proper exceptional control flow here.
+  builder.SetInsertPoint(error_bb);
+  auto trap_type = Intrinsic::getType(ctx, Intrinsic::trap);
+  auto trap_func = Intrinsic::getDeclaration(&module, Intrinsic::trap);
+  builder.CreateCall(trap_type, trap_func);
+  builder.CreateBr(cont_bb);
+
+  // Now pretend as if this new block is just the end of the block we
+  // started with.
+  builder.SetInsertPoint(cont_bb);
+}
+
+Expected<std::unique_ptr<DartInstruction>> InstCheckStackOverflow::Construct(
+    dart::SExpList* inst,
+    DartBasicBlockBuilder& bb_builder) {
+  // inst = (CheckStackoverflow)
+  return llvm::make_unique<InstCheckStackOverflow>();
+}
+
+void InstPushArgument::Build(BasicBlockBuilder& bb_builder) const {
+  bb_builder.PushArgument(bb_builder.GetValue(arg_));
+}
+
+Expected<std::unique_ptr<DartInstruction>> InstPushArgument::Construct(
+    dart::SExpList* inst,
+    DartBasicBlockBuilder& bb_builder) {
+  // inst = (PushArgument <arg>)
+  if (inst->Length() != 2) {
+    return CreateError("PushArgument should have exactly 1 argument");
+  }
+  dart::SExpSymbol* arg = inst->At(1)->AsSymbol();
+  if (!arg) {
+    return CreateError("Expected PushArgument's argument to be a symbol");
+  }
+  const DartValue* dvalue = bb_builder.GetDef(arg->value());
+  if (!dvalue) {
+    return CreateError(Twine(arg->value()) + " is not a valid symbol");
+  }
+  return llvm::make_unique<InstPushArgument>(dvalue);
+}
+
+void InstStaticCall::Build(BasicBlockBuilder& bb_builder) const {
+  // inst = (StaticCall <function-symbol> <arg> ...)  
+
+  SmallVector<Value*, 8> args;
+  size_t arg_count = args_len_;
+  while (arg_count) {
+    arg_count--;
+    args.push_back(bb_builder.PopArgument());
+  }
+  auto& builder = bb_builder.Builder();
+
+  // Hard code the function type for now.
+  auto& ctx = bb_builder.Context();
+  auto int8ty = IntegerType::getInt8Ty(ctx);
+  auto i8ptr = PointerType::get(int8ty, 0);
+  SmallVector<Type*, 8> arg_types;
+  arg_types.push_back(i8ptr);
+  auto print_type = FunctionType::get(Type::getVoidTy(ctx), arg_types, false);
+
+  // Get the function value we need.
+  auto func = bb_builder.GetValue(function_);
+  builder.CreateCall(print_type, func, args);
+}
+
+Expected<std::unique_ptr<DartInstruction>> InstStaticCall::Construct(
+    dart::SExpList* inst,
+    DartBasicBlockBuilder& bb_builder) {
+  // inst = (StaticCall <function_name> { args_len <N> })
+  if (inst->Length() != 2) {
+    return CreateError("StaticCall should have exactly 1 argument");
+  }
+  dart::SExpSymbol* func = inst->At(1)->AsSymbol();
+  if (!func) {
+    return CreateError("Expected StaticCall's argument to be a symbol");
+  }
+  const DartValue* dvalue = bb_builder.GetDef(func->value());
+  dart::SExpression* args_len_expr = inst->ExtraLookupValue("args_len");
+  // If args_len_expr isn't found args_len is assumed to be zero.
+  size_t args_len = 0;
+  if (args_len_expr) {
+    dart::SExpInteger* args_len_expr_int = args_len_expr->AsInteger();
+    if (args_len_expr_int) args_len = args_len_expr_int->value();
+  }
+  return llvm::make_unique<InstStaticCall>(dvalue, 1);
+}
+
+void InstReturn::Build(BasicBlockBuilder& bb_builder) const {
+  auto& builder = bb_builder.Builder();
+  builder.CreateRetVoid();
+}
+
+Expected<std::unique_ptr<DartInstruction>> InstReturn::Construct(
+    dart::SExpList* inst,
+    DartBasicBlockBuilder& bb_builder) {
+  // inst = (Return)
+  return llvm::make_unique<InstReturn>();
+}
+
+static Expected<StringMap<DartConstant>> MakeConstants(dart::SExpList* sexpr) {
+  dart::ApiZone zone;
+  StringMap<DartConstant> out;
+  for (intptr_t i = 1; i < sexpr->Length(); ++i) {
+    DartConstant constant;
+    dart::SExpList* def = sexpr->At(i)->AsList();
+    if (!def) {
+      return CreateError(Twine("Stray token in constants at location ") +
+                         Twine(i) + sexpr->At(i)->ToCString(zone.GetZone()));
+    }
+    if (def->Length() != 3) {
+      return CreateError("Constant definitions must have exactly 3 lines");
+    }
+    dart::SExpSymbol* def_symbol = def->At(0)->AsSymbol();
+    if (def_symbol->value() != StringRef("def")) {
+      return CreateError(
+          "first element in a constant definition expected to be `def`");
+    }
+    dart::SExpSymbol* def_name = def->At(1)->AsSymbol();
+    if (!def_name) {
+      return CreateError("element after `def` in constant expected to be name");
+    }
+    dart::SExpression* def_value = def->At(2);
+    if (def_value->IsString()) {
+      constant.str = def_value->AsString()->value();
+      constant.type = DartConstant::Type::String;
+    } else {
+      return CreateError("We can't yet handle that element type");
+    }
+    out[def_name->value()] = constant;
+  }
+  return out;
+}
+
+#define FOREACH_INSTRUCTION(M)                                                 \
+  M(CheckStackOverflow)                                                        \
+  M(PushArgument)                                                              \
+  M(StaticCall)                                                                \
+  M(Return)
+
+static Expected<std::unique_ptr<DartInstruction>> MakeInstruction(
+    dart::SExpList* sexpr,
+    DartBasicBlockBuilder& bb_builder) {
+  if (sexpr->Length() < 1)
+    return CreateError("An empty list can't be an instruction");
+  dart::SExpSymbol* inst_sym = sexpr->At(0)->AsSymbol();
+  if (!inst_sym)
+    return CreateError(
+        "Expected first element of list in instruction to be a symbol");
+  using CtorFunc = std::function<Expected<std::unique_ptr<DartInstruction>>(
+      dart::SExpList*, DartBasicBlockBuilder&)>;
+  CtorFunc ctor = StringSwitch<CtorFunc>(inst_sym->value())
+#define HANDLE_INSTRUCTION_CASE(INST) .Case(#INST, Inst##INST::Construct)
+      FOREACH_INSTRUCTION(HANDLE_INSTRUCTION_CASE);
+#undef HANDLE_INSTRUCTION_CASE
+  return ctor(sexpr, bb_builder);
+}
+
+static Expected<DartBlock> MakeBlock(dart::SExpList* sexpr,
+                                     DartFunction& function,
+                                     const StringMap<const DartValue*>& env) {
+  // Construct the basic block builder
+  DartBasicBlockBuilder bb_builder;
+  for (const auto& c : function.constants)
+    bb_builder.AddDef(c.getKey(), &c.getValue());
+  for (const auto& c : env)
+    bb_builder.AddDef(c.getKey(), c.getValue());
+
+  DartBlock out;
+
+  // Make sure we have a basic block and get the name
+  if (sexpr->Length() <= 2)
+    return CreateError("too few elements in basic block");
+  dart::SExpSymbol* block_name = sexpr->At(1)->AsSymbol();
+  if (!block_name)
+    return CreateError("expected block name after `block` symbol");
+  out.name = block_name->value();
+
+  // Now construct each instruction and add it to the basic block
+  for (intptr_t i = 2; i < sexpr->Length(); ++i) {
+    dart::SExpList* inst = sexpr->At(i)->AsList();
+    if (!inst)
+      return CreateError("stray token at element " + Twine(i) +
+                         " in basic block " + out.name);
+    auto inst_or = MakeInstruction(inst, bb_builder);
+    if (!inst_or) return inst_or.takeError();
+    out.instructions.emplace_back(std::move(*inst_or));
+  }
+  return out;
+}
+
+Expected<DartFunction> MakeFunction(dart::SExpression* sexpr,
+                                    const StringMap<const DartValue*>& env) {
+  // Basic checking that this s-expression looks like a function
+  dart::ApiZone zone;
+  dart::SExpList* flist = sexpr->AsList();
+  if (!flist) return CreateError("S-Expression was not a function list");
+  if (flist->Length() < 2)
+    return CreateError("S-Expression list was too short to be a function");
+  dart::SExpSymbol* function_symbol = flist->At(0)->AsSymbol();
+  if (function_symbol == nullptr ||
+      function_symbol->value() != StringRef("function"))
+    return CreateError(
+        "S-Expression cannot be a function as it does not start with "
+        "`function`");
+  dart::SExpSymbol* function_name = flist->At(1)->AsSymbol();
+  if (function_name == nullptr)
+    return CreateError("Expected symbol name after `function` symbol");
+
+  // Now we fill in all the details
+  DartFunction function;
+  function.name = function_name->value();
+  Optional<StringRef> normal_entry;
+  for (intptr_t i = 2; i < flist->Length(); ++i) {
+    dart::SExpList* chunk = flist->At(i)->AsList();
+    // Everything is a list so far so error out on other options
+    if (!chunk)
+      return CreateError(Twine("Stray token in function at location ") +
+                         Twine(i) + ": " +
+                         flist->At(i)->ToCString(zone.GetZone()));
+    dart::SExpSymbol* chunk_symbol = chunk->At(0)->AsSymbol();
+    if (!chunk_symbol)
+      return CreateError(Twine("Expected element ") + Twine(i) +
+                         " of function to start with a symbol");
+    StringRef chunk_tag = chunk_symbol->value();
+
+    if (chunk_tag == "constants") {
+      auto constants = MakeConstants(chunk);
+      if (!constants) return constants.takeError();
+      function.constants = std::move(*constants);
+    }
+
+    if (chunk_tag == "block") {
+      auto block = MakeBlock(chunk, function, env);
+      if (!block) return block.takeError();
+      StringRef name = block->name;
+      function.blocks[name] = std::move(*block);
+    }
+
+    if (chunk_tag == "normal-entry") {
+      if (chunk->Length() != 2)
+        return CreateError("Expected 1 argument to normal-entry");
+      dart::SExpSymbol* block_name = chunk->At(1)->AsSymbol();
+      if (!block_name)
+        return CreateError("expected block name after normal-entry symbol");
+      normal_entry = block_name->value();
+    }
+  }
+
+  if (normal_entry) {
+    auto iter = function.blocks.find(*normal_entry);
+    if (iter != function.blocks.end())
+      function.normal_entry = &iter->getValue();
+  } else {
+    function.normal_entry = nullptr;
+  }
+
+  return function;
+}
diff --git a/runtime/llvm_codegen/codegen/dart.h b/runtime/llvm_codegen/codegen/dart.h
new file mode 100644
index 0000000..1261a7b
--- /dev/null
+++ b/runtime/llvm_codegen/codegen/dart.h
@@ -0,0 +1,309 @@
+// 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.
+
+#ifndef RUNTIME_LLVM_CODEGEN_CODEGEN_DART_H_
+#define RUNTIME_LLVM_CODEGEN_CODEGEN_DART_H_
+
+#include <memory>
+#include <vector>
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/ValueSymbolTable.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/WithColor.h"
+#include "vm/compiler/backend/sexpression.h"
+
+// This file introduces several representations that exist between
+// S-Expressions and llvm IR. To explain how each part is intended
+// to be roughly translated using these I'll provide a mapping
+// showing how each part is translated.
+
+// At a high level two translations are very seamless:
+//
+// (function foo ...) -> DartFunction -> llvm::Function*
+// (block B ...) -> DartBlock -> (sort of) llvm::BasicBlock*
+//
+// Internally within a function constants are given names and are then used in
+// blocks. Each block additionally defines more names. Each of these names
+// needs to be mapped to a DartValue (more on that later) so a context to help
+// keep track of these name to DartValue mappings called a
+// DartBasicBlockBuilder exists. It is only used for to aid in the
+// (block B ...) -> DartBlock translation which is in turn used in the
+// (function foo ...) -> DartFunction translation. DartFunctions and DartBlocks
+// can be seen as validated representations of their S-Expression forms.
+
+// Within a DartBlock we have DartInstructions. Each DartInstruction either
+// has some effect (like calling a function or updating a value) or defines
+// a new name mapping it to a DartValue later. DartValues are referenced as
+// arguments to DartInstructions and map to llvm::Value*s. DartInstructions
+// have no analogue which they're directly translated to in code but they
+// do closely correspond mentally to llvm::Instruction*. The challenge is that
+// a DartInstruction might map to a near arbitrary number of llvm Instructions
+// and that mapping is very dependent on context. So instead of mapping them
+// to objects DartInstructions just know how to add their llvm Instructions to
+// an llvm::BasicBlock. These instructions might reference a verity of context
+// and so BasicBlockBuilder is passed in to provide them with this context.
+// Each DartInstruction is expected to already hold each DartValue that it
+// needs as previously supplied by the DartBasicBlockBuilder on construction.
+
+// An additional issue arises when translating DartInstructions into llvm IR.
+// Many require introducing control flow when lowered to the level of llvm IR
+// but this requires using multiple llvm::BasicBlock for a single DartBlock.
+// Luckily each DartInstruction that is not a terminator is expected to make it
+// possible for all non-exceptional control flow paths to wind up at a single
+// basic block. Since BasicBlockBuilder keeps track of a "current" basic block
+// via llvm::IRBuilder we simply ensure that after generating many blocks we
+// end each instruction which requires new basic blocks on this final basic
+// block that all generated blocks flow into. A picture better explains this:
+
+// Say you have a DartBlock B_1 it would then be mapped to llvm blocks that
+// look like this:
+//
+//                          B_1
+//                          / \
+//                         /   \
+//                 B_1_left    B_1_right
+//                         \   /
+//                          \ /
+//                         B_1_0
+//
+// And then we go on adding to B_1_0 as if it were the end of B_1 from before.
+
+// Each DartValue knows how to map itself to an llvm::Value. In llvm a Value
+// is really just anything you can give a name to in the IR but a DartValue
+// is intended to be more specific, it's a compile time representation of a
+// object, be it an integer, a tagged SMI, a pointer to a Dart Object, etc...
+// its intended to correspond to some actual object that we're computing on.
+
+// Class FunctionBuilder provides functionality for building
+// and LLVM function object including the ability to add a
+// named basic block, find an existing block, get the current
+// context/module and additionally retrieve llvm Values valid
+// in the current function.
+class FunctionBuilder {
+ public:
+  FunctionBuilder(llvm::LLVMContext& ctx,
+                  llvm::Module& mod,
+                  llvm::Function& func)
+      : ctx_(ctx), mod_(mod), func_(func) {}
+  llvm::LLVMContext& Context() { return ctx_; }
+  llvm::Module& Module() { return mod_; }
+  llvm::Value* GetSymbolValue(llvm::StringRef name) {
+    auto* symtab = func_.getValueSymbolTable();
+    return symtab->lookup(name);
+  }
+  llvm::BasicBlock* AddBasicBlock() {
+    return llvm::BasicBlock::Create(ctx_, "", &func_);
+  }
+  llvm::BasicBlock* AddBasicBlock(llvm::StringRef name) {
+    auto* bb = llvm::BasicBlock::Create(ctx_, name, &func_);
+    basic_blocks_[name] = bb;
+    return bb;
+  }
+  llvm::BasicBlock* GetBasicBlock(llvm::StringRef name) const {
+    auto iter = basic_blocks_.find(name);
+    if (iter != basic_blocks_.end()) return iter->getValue();
+    return nullptr;
+  }
+
+ private:
+  llvm::LLVMContext& ctx_;
+  llvm::Module& mod_;
+  llvm::Function& func_;
+  llvm::StringMap<llvm::BasicBlock*> basic_blocks_;
+};
+
+class BasicBlockBuilder;
+
+// TODO(jakehehrlich): Make this architecture dependent
+// Class DartThreadObject is used as a high level object for generating
+// code that reads fields from the thread object.
+class DartThreadObject {
+ public:
+  explicit DartThreadObject(BasicBlockBuilder& bb_builder)
+      : bb_builder_(bb_builder) {}
+
+  // StackLimit returns an llvm::Value representing the stack limit
+  // of the thread object.
+  llvm::Value* StackLimit() const;
+
+ private:
+  static constexpr intptr_t kThreadStackLimitOffset = 72;
+
+  BasicBlockBuilder& bb_builder_;
+
+  // GetOffset returns an llvm::Value* representing a pointer to a particular
+  // field of the thread object. It adds the specified offset to the thread
+  // pointer, and then casts to the specified type.
+  llvm::Value* GetOffset(llvm::Type* type, intptr_t offset) const;
+};
+
+class DartValue;
+
+// A class for keeping track of the basic block state and SSA values.
+// This is similar to IRBuilder but also keeps track of the argument stack and
+// basic block names.
+class BasicBlockBuilder {
+ public:
+  BasicBlockBuilder(llvm::BasicBlock* bb, FunctionBuilder& fb)
+      : fb_(fb), top_(bb), builder_(bb), thread_object_(*this) {}
+  llvm::LLVMContext& Context() { return fb_.Context(); }
+  llvm::Module& Module() { return fb_.Module(); }
+  llvm::IRBuilder<>& Builder() { return builder_; }
+  const DartThreadObject& ThreadObject() { return thread_object_; }
+  llvm::BasicBlock* AddBasicBlock() { return fb_.AddBasicBlock(); }
+  llvm::BasicBlock* GetBasicBlock(llvm::StringRef Name) const {
+    return fb_.GetBasicBlock(Name);
+  }
+  llvm::Value* GetSymbolValue(llvm::StringRef name) const {
+    return fb_.GetBasicBlock(name);
+  }
+  llvm::Value* GetValue(const DartValue* v);
+  void PushArgument(llvm::Value* v) { stack_.push_back(v); }
+  llvm::Value* PopArgument() {
+    llvm::Value* out = stack_.back();
+    stack_.pop_back();
+    return out;
+  }
+
+ private:
+  FunctionBuilder& fb_;
+  llvm::BasicBlock* top_;
+  llvm::SmallVector<llvm::Value*, 16> stack_;
+  llvm::IRBuilder<> builder_;
+  llvm::DenseMap<const DartValue*, llvm::Value*> values_;
+  DartThreadObject thread_object_;
+};
+
+// Class DartValue represents an SSA value from the Dart SSA
+// such that it can be converted into an llvm::Value*.
+class DartValue {
+ public:
+  virtual ~DartValue() {}
+  virtual llvm::Value* Make(BasicBlockBuilder& bb_builder) const = 0;
+  virtual llvm::Type* GetType(BasicBlockBuilder& bb_builder) const = 0;
+};
+
+// Class DartBasicBlockBuilder provides helpful context for going
+// from an S-Expression basic block to a DartBlock. It just lets
+// one lookup DartValue's by name at this time.
+class DartBasicBlockBuilder {
+ public:
+  void AddDef(llvm::StringRef name, const DartValue* v) { defs_[name] = v; }
+  const DartValue* GetDef(llvm::StringRef name) const {
+    auto iter = defs_.find(name);
+    if (iter != defs_.end()) return iter->getValue();
+    return nullptr;
+  }
+
+ private:
+  llvm::StringMap<const DartValue*> defs_;
+};
+
+// A DartConstant is a DartValue for a constant.
+class DartConstant : public DartValue {
+ public:
+  std::string str;
+  enum class Type { String };
+  Type type;
+
+  llvm::Value* Make(BasicBlockBuilder& bb_builder) const override;
+  llvm::Type* GetType(BasicBlockBuilder& bb_builder) const override;
+};
+
+// Class DartInstruction represents a step within a DartBasicBlock.
+// CheckStackOverflow or PushArgument are instructions. They contain
+// DartValues as arguments typically. SSA definitions are also
+// DartInstructions which assign DartValues to names in the function's
+// context.
+class DartInstruction {
+ public:
+  virtual ~DartInstruction();
+  virtual void Build(BasicBlockBuilder& bb_builder) const = 0;
+};
+
+// Class InstCheckStackOverflow is a DartInstruction that represents
+// an instance of a CheckStackOverflow instruction.
+class InstCheckStackOverflow : public DartInstruction {
+ public:
+  explicit InstCheckStackOverflow() {}
+  ~InstCheckStackOverflow() override {}
+  void Build(BasicBlockBuilder& bb_builder) const override;
+  static llvm::Expected<std::unique_ptr<DartInstruction>> Construct(
+      dart::SExpList* inst,
+      DartBasicBlockBuilder& bb_builder);
+};
+
+// Class InstPushArgument is a DartInstruction that represents
+// and instance of a PushArgument Instruction.
+class InstPushArgument : public DartInstruction {
+ public:
+  explicit InstPushArgument(const DartValue* arg) : arg_(arg) {}
+  ~InstPushArgument() override {}
+  void Build(BasicBlockBuilder& bb_builder) const override;
+  static llvm::Expected<std::unique_ptr<DartInstruction>> Construct(
+      dart::SExpList* inst,
+      DartBasicBlockBuilder& bb_builder);
+
+ private:
+  const DartValue* arg_;
+};
+
+// Class InstStaticCall is a DartInstruction that represents a
+// StaticCall instruction.
+class InstStaticCall : public DartInstruction {
+ public:
+  InstStaticCall(const DartValue* func, size_t args_len)
+      : function_(func), args_len_(args_len) {}
+  ~InstStaticCall() override {}
+  void Build(BasicBlockBuilder& bb_builder) const override;
+  static llvm::Expected<std::unique_ptr<DartInstruction>> Construct(
+      dart::SExpList* inst,
+      DartBasicBlockBuilder& bb_builder);
+
+ private:
+  const DartValue* function_;
+  size_t args_len_;
+};
+
+// Class InstReturn is a DartInstruction that represents a Return
+// instruction.
+class InstReturn : public DartInstruction {
+ public:
+  explicit InstReturn() {}
+  ~InstReturn() override {}
+  void Build(BasicBlockBuilder& bb_builder) const override;
+  static llvm::Expected<std::unique_ptr<DartInstruction>> Construct(
+      dart::SExpList* inst,
+      DartBasicBlockBuilder& bb_builder);
+};
+
+// Class DartBlock represents a validated basic block as parsed from
+// a (block ...) S-Expression.
+struct DartBlock {
+  std::string name;
+  std::vector<std::unique_ptr<DartInstruction>> instructions;
+};
+
+// Class DartFunction represents a validated function parsed from a
+// (function ...) S-Expression.
+struct DartFunction {
+  std::string name;
+  DartBlock* normal_entry;
+  llvm::StringMap<DartConstant> constants;
+  llvm::StringMap<DartBlock> blocks;
+};
+
+// MakeFunction takes an S-Expression and an environment of externally
+// defined DartValues and produces a DartFunction corresponding to the
+// S-Expression if everything is valid. If something about the syntax
+// of the S-Expression is invalid then the llvm::Expected will hold an
+// error explaining the issue.
+llvm::Expected<DartFunction> MakeFunction(
+    dart::SExpression* sexpr,
+    const llvm::StringMap<const DartValue*>& env);
+
+#endif  // RUNTIME_LLVM_CODEGEN_CODEGEN_DART_H
diff --git a/runtime/llvm_codegen/codegen/main.cc b/runtime/llvm_codegen/codegen/main.cc
index b45fcd2..4b469bc 100644
--- a/runtime/llvm_codegen/codegen/main.cc
+++ b/runtime/llvm_codegen/codegen/main.cc
@@ -2,15 +2,18 @@
 // for 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 <memory>
+#include "dart.h"
 
-#include "llvm/ADT/StringRef.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/Module.h"
-#include "llvm/IRReader/IRReader.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/Support/Host.h"
 #include "llvm/Support/InitLLVM.h"
-#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/WithColor.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/Target/TargetMachine.h"
+
+#include "vm/dart_api_state.h"
 
 using namespace llvm;
 
@@ -24,19 +27,136 @@
   exit(1);
 }
 
+LLVM_ATTRIBUTE_NORETURN void error(Error e) {
+  assert(e);
+  std::string buf;
+  raw_string_ostream os(buf);
+  logAllUnhandledErrors(std::move(e), os);
+  os.flush();
+  WithColor::error(errs(), tool_name) << buf;
+  exit(1);
+}
+
+LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) {
+  assert(EC);
+  error(createFileError(File, EC));
+}
+
+// We need a prelude function for printing to help get something functional
+// up off the ground.
+class DartPrint : public DartValue {
+ public:
+  Type* GetType(BasicBlockBuilder& bbb) const override {
+    auto& ctx = bbb.Context();
+    auto int8ty = IntegerType::getInt8Ty(ctx);
+    auto i8ptr = PointerType::get(int8ty, 0);
+    SmallVector<Type*, 1> arg_types;
+    arg_types.push_back(i8ptr);
+    return FunctionType::get(Type::getVoidTy(ctx), arg_types, false);
+  }
+  Value* Make(BasicBlockBuilder& bbb) const override {
+    auto ft = dyn_cast<FunctionType>(GetType(bbb));
+    if (ft == nullptr) return nullptr;
+    return Function::Create(ft, Function::ExternalLinkage, "dart:core::print",
+                            bbb.Module());
+  }
+};
+
+cl::opt<std::string> sexpr_file(cl::Positional,
+                                cl::desc("The input S-Expression file"));
+cl::opt<std::string> dump_obj(
+    "dump-obj",
+    cl::desc("Specifies where to output the .o file"));
+
+void Dump(Module* module, StringRef file, TargetMachine::CodeGenFileType type) {
+  legacy::PassManager pm;
+  std::error_code ec;
+  raw_fd_ostream out(file, ec);
+  if (ec) reportError(file, ec);
+  Triple target_triple{sys::getDefaultTargetTriple()};
+  TargetOptions options;
+  std::string err;
+  const Target* the_target =
+      TargetRegistry::lookupTarget(target_triple.getTriple(), err);
+  if (the_target == nullptr) error(err);
+  std::unique_ptr<TargetMachine> target(the_target->createTargetMachine(
+      target_triple.getTriple(), "generic", "", options, Reloc::PIC_));
+
+  if (target->addPassesToEmitFile(pm, out, nullptr, type, false))
+    error("couldn't add pass to emit file");
+  pm.run(*module);
+}
+
 }  // namespace
 
-int main(int argc, char** argv) {
+int main(int argc, const char** argv) {
+  // Init llvm
   InitLLVM X(argc, argv);
+  InitializeAllTargetInfos();
+  InitializeAllTargets();
+  InitializeAllTargetMCs();
+  InitializeAllAsmParsers();
+  InitializeAllAsmPrinters();
 
-  LLVMContext context;
-  SMDiagnostic err;
-  if (argc != 2) error("exactly one argument is taken");
+  // Basic init
   tool_name = argv[0];
-  std::unique_ptr<Module> mod = parseIRFile(argv[1], err, context);
-  if (mod == nullptr) {
-    err.print(tool_name.data(), errs());
-    exit(1);
+  cl::ParseCommandLineOptions(argc, argv, "llvm system compiler\n");
+
+  // Init dart
+  const char* err = Dart_SetVMFlags(0, argv + 2);
+  if (err != nullptr) error(Twine("Dart_SetVMFlags failed: ") + err);
+  Dart_InitializeParams init_params;
+  memset(&init_params, 0, sizeof(init_params));
+  init_params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION;
+  err = Dart_Initialize(&init_params);
+  if (err != nullptr) error(Twine("Dart Initialization failed: ") + err);
+
+  // Read in the file
+  auto file_or = MemoryBuffer::getFile(argv[1]);
+  if (!file_or) reportError(argv[1], file_or.getError());
+  std::unique_ptr<MemoryBuffer> file = std::move(file_or.get());
+
+  // Parse the file
+  dart::ApiZone zone;
+  dart::SExpParser parser(zone.GetZone(), file->getBufferStart(),
+                          file->getBufferSize());
+  dart::SExpression* root = parser.Parse();
+  if (root == nullptr)
+    error(Twine("SExpParser failed: ") + parser.error_message());
+
+  // Setup our basic prelude
+  StringMap<const DartValue*> prelude;
+  DartPrint print;
+  prelude["dart:core::print"] = &print;
+
+  // Convert the function into an error checked format
+  auto function_or = MakeFunction(root, prelude);
+  if (!function_or) error(function_or.takeError());
+  auto dart_function = std::move(*function_or);
+  if (!dart_function.normal_entry)
+    error(Twine("function ") + dart_function.name + " has no normal-entry");
+
+  // Setup state for output an LLVMModule
+  LLVMContext context;
+  auto module = llvm::make_unique<Module>(argv[1], context);
+  auto function_type = FunctionType::get(Type::getVoidTy(context), {}, false);
+  auto function = Function::Create(function_type, Function::ExternalLinkage,
+                                   dart_function.name, module.get());
+  FunctionBuilder fb{context, *module, *function};
+  for (auto& bbkey : dart_function.blocks) {
+    auto& bb = bbkey.getValue();
+    auto llvmbb = fb.AddBasicBlock(bb.name);
+    BasicBlockBuilder bbb{llvmbb, fb};
+    for (auto& inst : bb.instructions) {
+      inst->Build(bbb);
+    }
   }
-  mod->print(outs(), nullptr);
+
+  // Dump and print the file
+  if (!dump_obj.empty())
+    Dump(module.get(), dump_obj, LLVMTargetMachine::CGFT_ObjectFile);
+
+  module->print(llvm::outs(), nullptr);
+
+  return 0;
 }
diff --git a/runtime/llvm_codegen/test/bit/Inputs/basic_input.test b/runtime/llvm_codegen/test/bit/Inputs/basic_input.test
index 3889c3f..092dc80 100644
--- a/runtime/llvm_codegen/test/bit/Inputs/basic_input.test
+++ b/runtime/llvm_codegen/test/bit/Inputs/basic_input.test
@@ -1 +1 @@
-; RUN: %codegen %p/../../codegen/basic.ll
+; RUN: %{codegen} %p/../../codegen/Inputs/hello.sexp
diff --git a/runtime/llvm_codegen/test/bit/basic.test b/runtime/llvm_codegen/test/bit/basic.test
index e4989c6..88f0479 100644
--- a/runtime/llvm_codegen/test/bit/basic.test
+++ b/runtime/llvm_codegen/test/bit/basic.test
@@ -3,6 +3,6 @@
 ; RUN: cmp %t1 %t2
 ; RUN: echo this is a percent sign: % > %t3
 ; RUN: cmp %t3 %p/Inputs/percent.test
-; RUN: %bit %p/Inputs/basic_input.test %P > %t.test
+; RUN: %{bit} %p/Inputs/basic_input.test %P > %t.test
 ; RUN: echo Commands run: 1 > %t.test2
 ; RUN: cmp %t.test %t.test2
diff --git a/runtime/llvm_codegen/test/bit_test.gni b/runtime/llvm_codegen/test/bit_test.gni
index 38b7728..77f65fe 100644
--- a/runtime/llvm_codegen/test/bit_test.gni
+++ b/runtime/llvm_codegen/test/bit_test.gni
@@ -18,7 +18,7 @@
   assert(defined(invoker.tests), "tests must be defined for $target_name")
 
   action_foreach(target_name) {
-    script = "../../../build/gn_run_binary.py"
+    script = "//runtime/llvm_codegen/test/run_bit.py"
     sources = invoker.tests
 
     deps = [
@@ -33,10 +33,9 @@
       "$target_gen_dir/{{source_name_part}}}",
     ]
     args = [
-      "compiled_action",
-      rebase_path("${root_out_dir}/bit"),
-      "{{source}}",
-      rebase_path(target_gen_dir),
+      "--bit", rebase_path("${root_out_dir}/bit"),
+      "--test", "{{source}}",
+      "--out", rebase_path(target_gen_dir),
     ]
   }
 }
diff --git a/runtime/llvm_codegen/test/codegen/BUILD.gn b/runtime/llvm_codegen/test/codegen/BUILD.gn
index ab100e6..34dbba2 100644
--- a/runtime/llvm_codegen/test/codegen/BUILD.gn
+++ b/runtime/llvm_codegen/test/codegen/BUILD.gn
@@ -5,5 +5,5 @@
 import("../bit_test.gni")
 
 bit_test("codegen") {
-  tests = [ "basic.ll" ]
+  tests = [ "hello.test" ]
 }
diff --git a/runtime/llvm_codegen/test/codegen/Inputs/hello.expected b/runtime/llvm_codegen/test/codegen/Inputs/hello.expected
new file mode 100644
index 0000000..8ab686e
--- /dev/null
+++ b/runtime/llvm_codegen/test/codegen/Inputs/hello.expected
@@ -0,0 +1 @@
+Hello, World!
diff --git a/runtime/llvm_codegen/test/codegen/Inputs/hello.ll.expected b/runtime/llvm_codegen/test/codegen/Inputs/hello.ll.expected
new file mode 100644
index 0000000..187fd59
--- /dev/null
+++ b/runtime/llvm_codegen/test/codegen/Inputs/hello.ll.expected
@@ -0,0 +1,35 @@
+; ModuleID = '../../runtime/llvm_codegen/test/codegen/Inputs/hello.sexp'
+source_filename = "../../runtime/llvm_codegen/test/codegen/Inputs/hello.sexp"
+
+@0 = constant [14 x i8] c"Hello, World!\00"
+
+define void @"hello.dart::main"() {
+B1:
+  %0 = call i8* @llvm.stacksave()
+  %1 = ptrtoint i8* %0 to i64
+  %2 = load i64, i64 addrspace(256)* inttoptr (i64 72 to i64 addrspace(256)*)
+  %3 = icmp ult i64 %1, %2
+  br i1 %3, label %4, label %5
+
+4:                                                ; preds = %B1
+  call void @llvm.trap()
+  br label %5
+
+5:                                                ; preds = %4, %B1
+  call void @"dart:core::print"(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @0, i32 0, i32 0))
+  ret void
+}
+
+; Function Attrs: nounwind
+declare i8* @llvm.stacksave() #0
+
+; Function Attrs: cold noreturn nounwind
+declare void @llvm.trap() #1
+
+declare void @"dart:core::print"(i8*)
+
+; Function Attrs: nounwind
+declare void @llvm.stackprotector(i8*, i8**) #0
+
+attributes #0 = { nounwind }
+attributes #1 = { cold noreturn nounwind }
diff --git a/runtime/llvm_codegen/test/codegen/Inputs/hello.sexp b/runtime/llvm_codegen/test/codegen/Inputs/hello.sexp
new file mode 100644
index 0000000..c43c359
--- /dev/null
+++ b/runtime/llvm_codegen/test/codegen/Inputs/hello.sexp
@@ -0,0 +1,9 @@
+(function hello.dart::main
+  (constants
+    (def v2 "Hello, World!"))
+  (normal-entry B1)
+  (block B1
+    (CheckStackOverflow)
+    (PushArgument v2)
+    (StaticCall dart:core::print { args_len 1, env (v0 arg[0]), })
+    (Return v0)))
diff --git a/runtime/llvm_codegen/test/codegen/Inputs/runtime.S b/runtime/llvm_codegen/test/codegen/Inputs/runtime.S
new file mode 100644
index 0000000..7bb2c76
--- /dev/null
+++ b/runtime/llvm_codegen/test/codegen/Inputs/runtime.S
@@ -0,0 +1,38 @@
+// 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.
+
+.data
+
+.type _threadObject,@object
+.size _threadObject,1400
+_threadObject:
+  .fill 1400
+
+.text
+.file "runtime.S"
+
+.globl main
+.type main,@function
+
+.globl "dart:core::print"
+.type "dart:core::print",@function
+
+.globl arch_prctl
+.type arch_prctl,@function
+
+main:
+  movq %rsp, %rax
+  subq $0x1000, %rax
+  movq %rax, [_threadObject + 72]
+  # Pass ARCH_SET_GS
+  movq $0x1001, %rdi
+  # Pass $_threadObject
+  movq $_threadObject, %rsi
+  callq arch_prctl
+  callq "hello.dart::main"
+  ret
+
+"dart:core::print":
+  callq puts
+  ret
diff --git a/runtime/llvm_codegen/test/codegen/basic.ll b/runtime/llvm_codegen/test/codegen/basic.ll
deleted file mode 100644
index 2afc69b..0000000
--- a/runtime/llvm_codegen/test/codegen/basic.ll
+++ /dev/null
@@ -1,6 +0,0 @@
-; RUN: %codegen %s > %t
-
-define i32 @mult(i32, i32) {
-  %3 = mul i32 %0, %1
-  ret i32 %3
-}
diff --git a/runtime/llvm_codegen/test/codegen/hello.test b/runtime/llvm_codegen/test/codegen/hello.test
new file mode 100644
index 0000000..6b836d7
--- /dev/null
+++ b/runtime/llvm_codegen/test/codegen/hello.test
@@ -0,0 +1,6 @@
+; RUN: %{codegen} %p/Inputs/hello.sexp --dump-obj %t.o > %t.ll
+; RUN: diff %t.ll %p/Inputs/hello.ll.expected
+; RUN: %{clang} -g -c %p/Inputs/runtime.S -o %t.runtime.o
+; RUN: %{clang} %t.o %t.runtime.o -o %t.hello.exe
+; RUN: %t.hello.exe > %t.hello.exe.stdout
+; RUN: diff %t.hello.exe.stdout %p/Inputs/hello.expected
diff --git a/runtime/llvm_codegen/test/run_bit.py b/runtime/llvm_codegen/test/run_bit.py
new file mode 100644
index 0000000..29863f1
--- /dev/null
+++ b/runtime/llvm_codegen/test/run_bit.py
@@ -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.
+
+import subprocess
+import argparse
+
+parser = argparse.ArgumentParser(description="A tool to run the bit integration tester")
+parser.add_argument("--bit", help="Sets the path to bit")
+parser.add_argument("--test", help="Path to test to be run")
+parser.add_argument("--out", help="Path to out directory")
+args = parser.parse_args()
+
+subprocess.check_call([args.bit, args.test, args.out])
+
diff --git a/runtime/platform/address_sanitizer.h b/runtime/platform/address_sanitizer.h
index e621668..cc3f836 100644
--- a/runtime/platform/address_sanitizer.h
+++ b/runtime/platform/address_sanitizer.h
@@ -19,7 +19,7 @@
 extern "C" void __asan_unpoison_memory_region(void*, size_t);
 extern "C" void __lsan_register_root_region(const void* p, size_t size);
 extern "C" void __lsan_unregister_root_region(const void* p, size_t size);
-#define NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
+#define NO_SANITIZE_ADDRESS __attribute__((no_sanitize("address")))
 #define ASAN_UNPOISON(ptr, len) __asan_unpoison_memory_region(ptr, len)
 #define LSAN_REGISTER_ROOT_REGION(ptr, len)                                    \
   __lsan_register_root_region(ptr, len)
diff --git a/runtime/platform/atomic.h b/runtime/platform/atomic.h
index 72d563b..95fa2b8 100644
--- a/runtime/platform/atomic.h
+++ b/runtime/platform/atomic.h
@@ -5,12 +5,64 @@
 #ifndef RUNTIME_PLATFORM_ATOMIC_H_
 #define RUNTIME_PLATFORM_ATOMIC_H_
 
-#include "platform/globals.h"
+#include <atomic>
 
 #include "platform/allocation.h"
+#include "platform/globals.h"
 
 namespace dart {
 
+// Like std::atomic, but operations default to relaxed ordering instead of
+// acquire-release ordering.
+template <typename T>
+class RelaxedAtomic {
+ public:
+  constexpr RelaxedAtomic() : value_() {}
+  constexpr RelaxedAtomic(T arg) : value_(arg) {}           // NOLINT
+  RelaxedAtomic(const RelaxedAtomic& arg) : value_(arg) {}  // NOLINT
+
+  T load() const { return value_.load(std::memory_order_relaxed); }
+  void store(T arg) { value_.store(arg, std::memory_order_relaxed); }
+
+  T fetch_add(T arg) {
+    return value_.fetch_add(arg, std::memory_order_relaxed);
+  }
+  T fetch_sub(T arg) {
+    return value_.fetch_sub(arg, std::memory_order_relaxed);
+  }
+  T fetch_or(T arg) { return value_.fetch_or(arg, std::memory_order_relaxed); }
+  T fetch_and(T arg) {
+    return value_.fetch_and(arg, std::memory_order_relaxed);
+  }
+
+  bool compare_exchange_weak(T& expected, T desired) {  // NOLINT
+    return value_.compare_exchange_weak(expected, desired,
+                                        std::memory_order_relaxed,
+                                        std::memory_order_relaxed);
+  }
+  bool compare_exchange_strong(T& expected, T desired) {  // NOLINT
+    return value_.compare_exchange_strong(expected, desired,
+                                          std::memory_order_relaxed,
+                                          std::memory_order_relaxed);
+  }
+
+  operator T() const { return load(); }
+  T operator=(T arg) {
+    store(arg);
+    return arg;
+  }
+  T operator=(const RelaxedAtomic& arg) {
+    T loaded_once = arg;
+    store(loaded_once);
+    return loaded_once;
+  }
+  T operator+=(T arg) { return fetch_add(arg) + arg; }
+  T operator-=(T arg) { return fetch_sub(arg) - arg; }
+
+ private:
+  std::atomic<T> value_;
+};
+
 class AtomicOperations : public AllStatic {
  public:
   // Atomically fetch the value at p and increment the value at p.
@@ -30,10 +82,6 @@
   // Atomically decrement the value at p by 'value'.
   static void DecrementBy(intptr_t* p, intptr_t value);
 
-  // Atomically perform { tmp = *ptr; *ptr = (tmp OP value); return tmp; }.
-  static uint32_t FetchOrRelaxedUint32(uint32_t* ptr, uint32_t value);
-  static uint32_t FetchAndRelaxedUint32(uint32_t* ptr, uint32_t value);
-
   // Atomically compare *ptr to old_value, and if equal, store new_value.
   // Returns the original value at ptr.
   static uword CompareAndSwapWord(uword* ptr, uword old_value, uword new_value);
diff --git a/runtime/platform/atomic_android.h b/runtime/platform/atomic_android.h
index ef4e78a..cce35b9 100644
--- a/runtime/platform/atomic_android.h
+++ b/runtime/platform/atomic_android.h
@@ -46,16 +46,6 @@
   __sync_fetch_and_sub(p, value);
 }
 
-inline uint32_t AtomicOperations::FetchOrRelaxedUint32(uint32_t* ptr,
-                                                       uint32_t value) {
-  return __atomic_fetch_or(ptr, value, __ATOMIC_RELAXED);
-}
-
-inline uint32_t AtomicOperations::FetchAndRelaxedUint32(uint32_t* ptr,
-                                                        uint32_t value) {
-  return __atomic_fetch_and(ptr, value, __ATOMIC_RELAXED);
-}
-
 inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
                                                   uword old_value,
                                                   uword new_value) {
diff --git a/runtime/platform/atomic_fuchsia.h b/runtime/platform/atomic_fuchsia.h
index 8688987..6af88f6 100644
--- a/runtime/platform/atomic_fuchsia.h
+++ b/runtime/platform/atomic_fuchsia.h
@@ -43,16 +43,6 @@
   __sync_fetch_and_sub(p, value);
 }
 
-inline uint32_t AtomicOperations::FetchOrRelaxedUint32(uint32_t* ptr,
-                                                       uint32_t value) {
-  return __atomic_fetch_or(ptr, value, __ATOMIC_RELAXED);
-}
-
-inline uint32_t AtomicOperations::FetchAndRelaxedUint32(uint32_t* ptr,
-                                                        uint32_t value) {
-  return __atomic_fetch_and(ptr, value, __ATOMIC_RELAXED);
-}
-
 inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
                                                   uword old_value,
                                                   uword new_value) {
diff --git a/runtime/platform/atomic_linux.h b/runtime/platform/atomic_linux.h
index c309af7..b4bd342 100644
--- a/runtime/platform/atomic_linux.h
+++ b/runtime/platform/atomic_linux.h
@@ -46,16 +46,6 @@
   __sync_fetch_and_sub(p, value);
 }
 
-inline uint32_t AtomicOperations::FetchOrRelaxedUint32(uint32_t* ptr,
-                                                       uint32_t value) {
-  return __atomic_fetch_or(ptr, value, __ATOMIC_RELAXED);
-}
-
-inline uint32_t AtomicOperations::FetchAndRelaxedUint32(uint32_t* ptr,
-                                                        uint32_t value) {
-  return __atomic_fetch_and(ptr, value, __ATOMIC_RELAXED);
-}
-
 inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
                                                   uword old_value,
                                                   uword new_value) {
diff --git a/runtime/platform/atomic_macos.h b/runtime/platform/atomic_macos.h
index 340ed40..ba4433c 100644
--- a/runtime/platform/atomic_macos.h
+++ b/runtime/platform/atomic_macos.h
@@ -46,16 +46,6 @@
   __sync_fetch_and_sub(p, value);
 }
 
-inline uint32_t AtomicOperations::FetchOrRelaxedUint32(uint32_t* ptr,
-                                                       uint32_t value) {
-  return __atomic_fetch_or(ptr, value, __ATOMIC_RELAXED);
-}
-
-inline uint32_t AtomicOperations::FetchAndRelaxedUint32(uint32_t* ptr,
-                                                        uint32_t value) {
-  return __atomic_fetch_and(ptr, value, __ATOMIC_RELAXED);
-}
-
 inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
                                                   uword old_value,
                                                   uword new_value) {
diff --git a/runtime/platform/atomic_win.h b/runtime/platform/atomic_win.h
index bbef085..6431f4c 100644
--- a/runtime/platform/atomic_win.h
+++ b/runtime/platform/atomic_win.h
@@ -102,18 +102,6 @@
 #endif
 }
 
-inline uint32_t AtomicOperations::FetchOrRelaxedUint32(uint32_t* ptr,
-                                                       uint32_t value) {
-  return static_cast<uint32_t>(InterlockedOrNoFence(
-      reinterpret_cast<LONG*>(ptr), static_cast<LONG>(value)));
-}
-
-inline uint32_t AtomicOperations::FetchAndRelaxedUint32(uint32_t* ptr,
-                                                        uint32_t value) {
-  return static_cast<uint32_t>(InterlockedAndNoFence(
-      reinterpret_cast<LONG*>(ptr), static_cast<LONG>(value)));
-}
-
 inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
                                                   uword old_value,
                                                   uword new_value) {
diff --git a/runtime/platform/memory_sanitizer.h b/runtime/platform/memory_sanitizer.h
index f9e6f0d..402bdcb 100644
--- a/runtime/platform/memory_sanitizer.h
+++ b/runtime/platform/memory_sanitizer.h
@@ -15,7 +15,7 @@
 extern "C" void __msan_unpoison(const volatile void*, size_t);
 #define MSAN_POISON(ptr, len) __msan_poison(ptr, len)
 #define MSAN_UNPOISON(ptr, len) __msan_unpoison(ptr, len)
-#define NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
+#define NO_SANITIZE_MEMORY __attribute__((no_sanitize("memory")))
 #else  // __has_feature(memory_sanitizer)
 #define MSAN_POISON(ptr, len)                                                  \
   do {                                                                         \
diff --git a/runtime/platform/platform_sources.gni b/runtime/platform/platform_sources.gni
index 8a1b83e..cc02ccb 100644
--- a/runtime/platform/platform_sources.gni
+++ b/runtime/platform/platform_sources.gni
@@ -33,6 +33,7 @@
   "syslog_win.cc",
   "text_buffer.cc",
   "text_buffer.h",
+  "thread_sanitizer.h",
   "unicode.cc",
   "unicode.h",
   "utils.cc",
diff --git a/runtime/platform/thread_sanitizer.h b/runtime/platform/thread_sanitizer.h
new file mode 100644
index 0000000..e8c4fcf
--- /dev/null
+++ b/runtime/platform/thread_sanitizer.h
@@ -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.
+
+#ifndef RUNTIME_PLATFORM_THREAD_SANITIZER_H_
+#define RUNTIME_PLATFORM_THREAD_SANITIZER_H_
+
+#include "platform/globals.h"
+
+#if defined(__has_feature)
+#if __has_feature(thread_sanitizer)
+#define USING_THREAD_SANITIZER
+#endif
+#endif
+
+#if defined(USING_THREAD_SANITIZER)
+#define NO_SANITIZE_THREAD __attribute__((no_sanitize("thread")))
+#else
+#define NO_SANITIZE_THREAD
+#endif
+
+#endif  // RUNTIME_PLATFORM_THREAD_SANITIZER_H_
diff --git a/runtime/runtime_args.gni b/runtime/runtime_args.gni
index 35e6e7c..381d94a 100644
--- a/runtime/runtime_args.gni
+++ b/runtime/runtime_args.gni
@@ -80,8 +80,8 @@
     dart_component_kind = "static_library"
   }
 
-  # Controls whether the VM uses bytecode.
-  dart_platform_bytecode = true
+  # Whether the VM's platform dill file contains bytecode.
+  dart_platform_bytecode = false
 
   # Whether the VM includes the kernel service in all modes (debug, release,
   # product).
diff --git a/runtime/tests/vm/dart/extension_names_test.dart b/runtime/tests/vm/dart/extension_names_test.dart
new file mode 100644
index 0000000..77414da
--- /dev/null
+++ b/runtime/tests/vm/dart/extension_names_test.dart
@@ -0,0 +1,103 @@
+// 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 ensures stack traces have user friendly names from extension
+// functions.
+
+import 'dart:core';
+import "package:expect/expect.dart";
+
+class C<T> {
+  static int tracefunc() {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      Expect.isTrue(s.toString().contains('C.tracefunc'));
+      Expect.isTrue(s.toString().contains('ext.sfld'));
+    }
+    return 10;
+  }
+
+  static int ld = C.tracefunc();
+}
+
+extension ext<T> on C<T> {
+  func() {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      Expect.isTrue(s.toString().contains('ext.func'));
+    }
+  }
+
+  get prop {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      Expect.isTrue(s.toString().contains('ext.prop'));
+    }
+  }
+
+  set prop(value) {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      Expect.isTrue(s.toString().contains('ext.prop='));
+    }
+  }
+
+  operator +(val) {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      Expect.isTrue(s.toString().contains('ext.+'));
+    }
+  }
+
+  operator -(val) {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      Expect.isTrue(s.toString().contains('ext.-'));
+    }
+  }
+
+  static int sfld = C.tracefunc();
+  static sfunc() {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      Expect.isTrue(s.toString().contains('ext.sfunc'));
+    }
+  }
+
+  static get sprop {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      Expect.isTrue(s.toString().contains('ext.sprop'));
+    }
+  }
+
+  static set sprop(value) {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      Expect.isTrue(s.toString().contains('ext.sprop='));
+    }
+  }
+}
+
+main() {
+  C<int> c = new C<int>();
+  c.func();
+  c.prop;
+  c.prop = 10;
+  ext.sfunc();
+  ext.sprop;
+  ext.sprop = 10;
+  ext.sfld;
+  c + 1;
+  c - 1;
+}
diff --git a/runtime/tests/vm/dart/extension_unnamed_names_test.dart b/runtime/tests/vm/dart/extension_unnamed_names_test.dart
new file mode 100644
index 0000000..a38966d
--- /dev/null
+++ b/runtime/tests/vm/dart/extension_unnamed_names_test.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.
+
+// Test that ensures stack traces have user friendly names from extension
+// functions.
+
+import 'dart:core';
+import "package:expect/expect.dart";
+
+class C {
+  static int tracefunc() {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      Expect.isTrue(s.toString().contains('C.tracefunc'));
+      Expect.isTrue(s.toString().contains('ext.sfld'));
+    }
+    return 10;
+  }
+
+  static int ld = C.tracefunc();
+}
+
+extension on C {
+  func() {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      Expect.isTrue(s.toString().contains('_extension#0.func'));
+    }
+  }
+
+  get prop {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      Expect.isTrue(s.toString().contains('_extension#0.prop'));
+    }
+  }
+
+  set prop(value) {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      Expect.isTrue(s.toString().contains('_extension#0.prop='));
+    }
+  }
+
+  operator +(val) {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      Expect.isTrue(s.toString().contains('_extension#0.+'));
+    }
+  }
+
+  operator -(val) {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      Expect.isTrue(s.toString().contains('_extension#0.-'));
+    }
+  }
+}
+
+extension on C {
+  bar() {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      Expect.isTrue(s.toString().contains('_extension#1.bar'));
+    }
+  }
+}
+
+main() {
+  C c = new C();
+  c.func();
+  c.prop;
+  c.prop = 10;
+  c + 1;
+  c - 1;
+  c.bar();
+}
diff --git a/runtime/tests/vm/dart/regress38467_test.dart b/runtime/tests/vm/dart/regress38467_test.dart
new file mode 100644
index 0000000..5bf5086
--- /dev/null
+++ b/runtime/tests/vm/dart/regress38467_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.
+
+// Regression test for dartbug.com/38467: check that we don't consider
+// list[const] to be an access via constant index when list is (potentially)
+// a view.
+
+// VMOptions=--optimization_counter_threshold=10 --deterministic
+
+import 'dart:typed_data';
+
+import 'package:expect/expect.dart';
+
+Float64List foo = new Float64List(2);
+Float64List bar = new Float64List(2);
+
+void prepare() {
+  bar = new Float64List.view(foo.buffer, 8);
+}
+
+@pragma('vm:never-inline')
+testMain(Float64List xfoo, Float64List xbar) {
+  xfoo[1] = 1.0;
+  xbar[0] = 2.0;
+  return xfoo[1];
+}
+
+void main() {
+  prepare();
+  Expect.equals(2.0, testMain(foo, bar));
+}
diff --git a/runtime/tests/vm/dart/regress38654_test.dart b/runtime/tests/vm/dart/regress38654_test.dart
new file mode 100644
index 0000000..4aed202
--- /dev/null
+++ b/runtime/tests/vm/dart/regress38654_test.dart
@@ -0,0 +1,606 @@
+// 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.
+
+// See https://github.com/dart-lang/sdk/issues/38654 for context.
+
+// The Dart Project Fuzz Tester (1.53).
+// Program generated as:
+//   dart dartfuzz.dart --seed 194851581 --no-fp --no-ffi
+
+import 'dart:async';
+import 'dart:cli';
+import 'dart:collection';
+import 'dart:convert';
+import 'dart:core';
+import 'dart:io';
+import 'dart:isolate';
+import 'dart:math';
+import 'dart:typed_data';
+
+Map<int, String> var0 = {
+  39: 'sl2a(',
+  29: 'HGYdMd',
+  93: '\u2665',
+  97: 'hJ',
+  38: 'O',
+  25: '',
+  40: ''
+};
+int var1 = 56;
+int var2 = -9;
+bool var3 = false;
+int var4 = -77;
+double var5 = 0.9130097229882881;
+String var6 = '\u2665g';
+List<int> var7 = [-4294967280, -46, -51, 13, -77, -20];
+Set<int> var8 = {
+  -9223372036854775680,
+  25,
+  -43,
+  2,
+  -57,
+  -9223372030412324865,
+  4294967423,
+  -39
+};
+Map<int, String> var9 = {90: 'DXbRR', 8: 's\u2665y', 51: '0wumJ', 33: 'aee'};
+
+String foo0() {
+  {
+    int loc0 = 79;
+    while (--loc0 > 0) {
+      for (int loc1 in ((var7 +
+              [
+                -51,
+                Int32x4.wwzy,
+                (((var3 ? (--var2) : 21) < -40)
+                    ? (var3 ? var2 : var7[var1])
+                    : (var1--)),
+                ((var3
+                        ? Float32x4.wyyy
+                        : var7[
+                            (false ? var4 : ZLibOption.DEFAULT_WINDOW_BITS)]) <<
+                    var7[var7[-32769]]),
+                (var3 ? 8 : var7[-9223372036854775680]),
+                (Int32x4.xxww ^ Int32x4.zzyy)
+              ]) ??
+          ((!((var0 !=
+                  {
+                    96: 'r&\u2665P',
+                    94: ('JXX ' + var6),
+                    62: '\u26656',
+                    35: ListBase.listToString(var7)
+                  })))
+              ? ((var3 ? var7 : (true ? var7 : var7)) ??
+                  [
+                    (false ? var2 : -66),
+                    -55,
+                    (-(var7[loc0])),
+                    var7[-12],
+                    ((((27 + var1)).isInfinite
+                            ? var3
+                            : (var3 ? (var9[var7[-88]]).isEmpty : var3))
+                        ? -4294934528
+                        : var1),
+                    -40,
+                    var7[var7[var7[Int32x4.wxyw]]],
+                    14
+                  ])
+              : [Float32x4.yxyy]))) {
+        /*
+         * Multi-line
+         * comment.
+         */
+        {
+          int loc2 = 67;
+          while (--loc2 > 0) {
+            var8 = {loc1, 62, -37, Float32x4.yxwz, -42};
+          }
+        }
+        var9.forEach((loc2, loc3) {
+          var7 = var7;
+          try {
+            loc3 ??= 'tSWbA';
+          } catch (exception, stackTrace) {
+            for (int loc4 in [
+              ((!((((-82 * var7[-28])).toString() == (var0[31] ?? var6))))
+                  ? (--var2)
+                  : (--var4))
+            ]) {
+              var7[Int32x4.wxzx] ~/= Int32x4.ywwx;
+            }
+            var3 ??= var3;
+          } finally {
+            var0 ??= var9;
+          }
+        });
+      }
+    }
+  }
+  return ((var3 &&
+          (((var3 ? true : (var3 || var3)) ? false : false)
+              ? true
+              : (!((false && false)))))
+      ? 'V-5p'
+      : (((Float32x4.xwwx > var7[var2])
+              ? var6
+              : var9[(((--var2)).isEven ? -90 : (++var2))]) ??
+          (var3 ? '' : '!5s#rtD')));
+}
+
+Set<int> foo1(int par1, bool par2) {
+  // Single-line comment.
+  {
+    int loc0 = 68;
+    while (--loc0 > 0) {
+      {
+        List<int> loc1 = [
+          var1,
+          -13,
+          (false ? ((~(19)) - ((!(true)) ? (par1++) : -89)) : (~((var2--)))),
+          Float32x4.yzww,
+          var7[(~((--par1)))],
+          (-99 % par1),
+          (true ? (~(var7[par1])) : Int32x4.xyxw)
+        ];
+        for (int loc2 in var8) {
+          var7[16] <<= Float32x4.yyyx;
+        }
+        for (int loc2 = 0; loc2 < 33; loc2++) {
+          if (var3) {
+            var0 = (Map.unmodifiable(var9) ??
+                (Map.unmodifiable(var9) ??
+                    Map.from({6: var9[var1], 28: foo0(), 36: '8+'})));
+            var9[((-93 * loc1[loc2]) +
+                (((!((!(par2)))) || (!(par2)))
+                    ? (var4 ~/ JsonUtf8Encoder.DEFAULT_BUFFER_SIZE)
+                    : -9223372032559775745))] ??= var6;
+          }
+          var3 = ((!((loc1[loc0] != (false ? (--var4) : var1)))) ||
+              ('').endsWith('xTYEp\u2665'));
+        }
+      }
+      for (int loc1 in var7) {
+        var7[Float32x4.ywzy] >>= var2;
+        /*
+         * Multi-line
+         * comment.
+         */
+        var8 = (((false ? var8 : {var1, Float32x4.xwyw}) ??
+                ({(Int32x4.wxyy & var7[(par1--)])} ??
+                    (var3
+                        ? {var7[73], 20, var4, (var7[(-20 | loc1)] * 84), 47}
+                        : (par2
+                            ? {
+                                8,
+                                -66,
+                                (((var7[var7[-56]])
+                                            .toRadixString(Int32x4.wyxx) !=
+                                        (('j' ?? 'r')).toLowerCase())
+                                    ? var7[var7[(var2++)]]
+                                    : (-(Duration.microsecondsPerDay))),
+                                (~(((!(true))
+                                    ? (false
+                                        ? (++var2)
+                                        : var7[ZLibOption.STRATEGY_FILTERED])
+                                    : Float32x4.xxyz))),
+                                (var3
+                                    ? (true
+                                        ? (-95 -
+                                            (-25 ??
+                                                ((false ? true : var3)
+                                                    ? Int32x4.xxww
+                                                    : var7[-29])))
+                                        : (var2++))
+                                    : -34)
+                              }
+                            : ({(++var4), par1, (-81 % var7[-54])})
+                                .toSet())))) ??
+            {
+              (~((-((loc1++))))),
+              (var7[var7[4295032832]] - RawSocketOption.levelIPv4)
+            });
+      }
+    }
+  }
+  return {
+    var7[var2],
+    var2,
+    (-(((par2 && par2) ? Int32x4.ywzw : Float32x4.wywx))),
+    ((!(NetworkInterface.listSupported))
+        ? (--var4)
+        : (((var6).isEmpty
+                ? (-73 * ((var7[var4]).isOdd ? Float32x4.xwww : -63))
+                : -4) -
+            (~(69)))),
+    (((true
+                ? (true
+                    ? -9223372032559808257
+                    : (~((par2 ? (var1--) : (false ? var7[-4] : var1)))))
+                : 27) <<
+            Float32x4.xyzy) -
+        ((~(var7[Float32x4.xyzz])) &
+            (((par2 ? true : false) ? par2 : true)
+                ? 44
+                : ((!(par2)) ? -57 : var7[var2])))),
+    (MapBase.mapToString((Map.from({
+              77: ((!(false)) ? var6 : var0[var7[var7[var7[-63]]]]),
+              87: '9vj',
+              50: 'e\u26655-',
+              46: var9[-32],
+              96: var6
+            }) ??
+            {
+              32: var0[-9223372032559742976],
+              4: SetBase.setToString(var8),
+              67: var0[Int32x4.yxww],
+              53: var9[53],
+              91: var6,
+              17: '2gtffn'
+            })))
+        .length
+  };
+}
+
+String foo2(Map<int, String> par1, bool par2) {
+  try {
+    par2 = (false
+        ? false
+        : (SecurityContext.alpnSupported
+            ? false
+            : (var3 ? ('aXL').isNotEmpty : (77).isNegative)));
+    if ((((++var4) ~/ (var4 & var1))).isEven) {
+      /*
+       * Multi-line
+       * comment.
+       */
+      var7 ??= (((((-(var7[-2]))).toString() ?? foo0()) ??
+              (true
+                  ? (par1[(-57 + (var7[52] | -91))] + var9[57])
+                  : Uri.decodeFull((false
+                      ? '17'
+                      : (8).toStringAsExponential(var7[var7[8]]))))))
+          .codeUnits;
+    }
+  } catch (exception, stackTrace) {
+    {
+      bool loc0 = ({
+        61: String.fromEnvironment(('K4\u2665dc0' + var6)),
+        85: ((!(true)) ? 'I&P' : par1[(~((-((++var4)))))])
+      }).isNotEmpty;
+      {
+        Map<int, String> loc1 =
+            Map.from({55: (true ? '' : 'ZoDx\u{1f600}'), 82: foo0()});
+
+        /// Single-line documentation comment.
+        var3 = var3;
+      }
+      {
+        int loc1 = 81;
+        while (--loc1 > 0) {
+          var3 = (!((List.filled(38, 87) !=
+              ((false ? (true ? loc0 : true) : var3) ? var7 : var7))));
+          try {
+            par2 = var3;
+            switch (loc1) {
+              case 1947756698:
+                {
+                  var7 = [
+                    [(--var1), -74, (-(Float32x4.ywyw))][((-(38)) | (var2--))],
+                    Float32x4.yyzy,
+                    (Int32x4.yxzx % Int32x4.ywyx),
+                    var4,
+                    (loc0 ? (var1--) : Float32x4.xzxy),
+                    (-((~(-15))))
+                  ];
+
+                  /// Single-line documentation comment.
+                  throw {
+                    (true ? ((var4++) ~/ (-69 ?? 78)) : (var1--)),
+                    (--var1),
+                    (-((var2--))),
+                    (-82 % (-30).bitLength),
+                    14,
+                    32768,
+                    Int32x4.zxwy
+                  };
+                }
+                break;
+              case 1947756704:
+                {
+                  if (true) {
+                    break;
+                  }
+                }
+                break;
+            }
+          } catch (exception, stackTrace) {
+            var6 = 'YgW\u{1f600}';
+            if ((!(((true ? loc0 : var3) &&
+                ((var3 ? ((var1++)).isFinite : par2) || var3))))) {
+              try {
+                return foo0();
+              } catch (exception, stackTrace) {
+                var6 = foo0();
+              }
+              par1 = ((par2 ? (par1 ?? Map.identity()) : var9) ?? var9);
+            } else {
+              var7 ??= var7;
+              return 'ACaB#Z1';
+            }
+          }
+        }
+      }
+    }
+    for (int loc0 = 0; loc0 < 15; loc0++) {
+      var7[(-(((Uint64List.bytesPerElement).isFinite ? -12 : -46)))] ~/= (true
+          ? loc0
+          : (~((var7[(14 >> (-((var1--))))] ^ (9223372032559808639 ?? loc0)))));
+    }
+  } finally {
+    /*
+     * Multi-line
+     * comment.
+     */
+    try {
+      {
+        int loc0 = 73;
+        while (--loc0 > 0) {
+          {
+            int loc1 = 0;
+            do {
+              var4 <<= loc0;
+              for (int loc2 in var8) {
+                par2 = true;
+                par2 ??= (foo0()).isEmpty;
+              }
+            } while (++loc1 < 73);
+          }
+          var9 = var0;
+        }
+      }
+      for (int loc0 = 0; loc0 < 96; loc0++) {
+        /// Single-line documentation comment.
+        try {
+          par2 ??= ('(b').endsWith('x-f76ee');
+          var3 = var3;
+        } catch (exception, stackTrace) {
+          var8 ??= foo1((var3 ? 51 : (false ? Int32x4.zzxy : (-((~(-84)))))),
+              (NetworkInterface.listSupported || true));
+        }
+      }
+    } catch (exception, stackTrace) {
+      for (int loc0 in [
+        (~((-(((par2 ? Int32x4.zzzw : var2) * (-(89))))))),
+        -14,
+        -88,
+        (var4++),
+        (var7[((var7[Float32x4.xxxx] % (~(var7[var4]))) | -16)] |
+            (var7[Float32x4.zwwz] ^ -9223372036854775681))
+      ]) {
+        var7[(par2 ? 60 : (-7 >> -53))] ??= Int32x4.yzxw;
+        for (int loc1
+            in (var3 ? (((loc0 * var7[16])).toString()).codeUnits : var7)) {
+          var0.forEach((loc2, loc3) {
+            var3 ??= (foo0()).isNotEmpty;
+            throw (var4++);
+          });
+        }
+      }
+    } finally {
+      try {
+        var8 = ((!(true))
+            ? {Float32x4.zzwy, 67, -6, 85}
+            : foo1(Float32x4.zwxy, var3));
+        var8 = foo1(
+            (-54).abs(),
+            ((var3 ? true : (!(var3)))
+                ? (!((Uri.encodeFull('aILQc')).endsWith('+7o0Q6b')))
+                : ((true ? ('bEIx').endsWith(par1[var2]) : par2)
+                    ? false
+                    : ({
+                          -77,
+                          (false ? -9223372036854775792 : 4294968296),
+                          var4,
+                          var7[var7[var7[var2]]]
+                        } !=
+                        {
+                          var7[-80],
+                          (true ? var7[22] : (-(58))),
+                          -77,
+                          (var7[Int32x4.wxwz] ~/ 66)
+                        }))));
+      } catch (exception, stackTrace) {
+        try {
+          var6 ??= par1[(('R12').isNotEmpty
+              ? (par2 ? 4294967396 : var2)
+              : (((var0).isEmpty ? true : par2) ? var4 : var2))];
+          var8 ??= (var8 ??
+              {
+                (~(((var7[var2] ?? 86) >>
+                    (((-(var7[var1]))).isNaN
+                        ? (var3 ? (false ? -4294901760 : (-(var7[32]))) : var1)
+                        : var4)))),
+                Int32x4.wyzy
+              });
+        } catch (exception, stackTrace) {
+          var9 = (Map.of({
+                59: var6,
+                3: var0[DateTime.may],
+                49: par1[var2],
+                71: '6',
+                77: ((!(true)) ? ('QB\u2665OU6' ?? 'r-\u2665') : foo0()),
+                88: foo0()
+              }) ??
+              var0);
+          var6 ??= ((('').substring(40, (~(Int32x4.yxxx))) ??
+                  ((var9[81] ?? '0(G') + ('u-+').toLowerCase())))
+              .trimRight();
+        }
+        var7 = [-9223372032559808512];
+      } finally {
+        var4 -= var7[(++var2)];
+      }
+      var0.forEach((loc0, loc1) {
+        switch (Int32x4.xyyw) {
+          case 2310807338:
+            {
+              var9[((var7[var7[var1]] % (~(49))) & (~((var7[34]).toInt())))] ??=
+                  ('5j' ?? 'jfHUh');
+              var8 ??= ((!((!(var3))))
+                  ? (par2
+                      ? var8
+                      : ((var7[(-38 - (var3 ? -38 : -91))]).isNegative
+                          ? (true
+                              ? (({-83, loc0} ??
+                                      {
+                                        var1,
+                                        27,
+                                        -73,
+                                        var7[var4],
+                                        (-88 +
+                                            (~(((var3
+                                                    ? ((-(-51)) + -60)
+                                                    : var7[-21]) ??
+                                                -65))))
+                                      }))
+                                  .difference({
+                                  (-(Float32x4.yxzw)),
+                                  (--var2),
+                                  Int32x4.wywz,
+                                  (-(((true
+                                          ? (true
+                                              ? (true ? (!(var3)) : true)
+                                              : true)
+                                          : (var8 != {(~(loc0)), 28, -96}))
+                                      ? (par2
+                                          ? ((par2
+                                                  ? var7[var7[(++var4)]]
+                                                  : (var4--)) +
+                                              57)
+                                          : ((((var3 ? false : true)
+                                                      ? par2
+                                                      : par2)
+                                                  ? (var4 * var7[-74])
+                                                  : var2) >>
+                                              (false ? 63 : -23)))
+                                      : (false ? -6 : (par2 ? 10 : var2))))),
+                                  -35,
+                                  (-(-92)),
+                                  var7[DateTime.saturday]
+                                })
+                              : Set.identity())
+                          : (par2
+                              ? {(-((var2 | (-(-57)))))}
+                              : ((var4 < 10)
+                                  ? foo1(var7[8], par2)
+                                  : (var3
+                                      ? {96, 82, var7[(++var4)]}
+                                      : {var2})))))
+                  : foo1(
+                      ((false || true)
+                          ? loc0
+                          : ((var3
+                                  ? 49
+                                  : ((var2 ?? var7[(-((~(23))))]) >> 97)) <<
+                              var7[34])),
+                      (!(par2))));
+            }
+            break;
+          case 2310807345:
+            {
+              var8 ??= ((foo1((false ? var1 : (var4++)), (!(par2))) ??
+                      ((var8 ??
+                              {
+                                var4,
+                                -22,
+                                (-(var7[((~(Float32x4.zyzx)) | var7[-23])])),
+                                -35
+                              }) ??
+                          {var1, 21, var2, var7[Float32x4.ywyw], loc0})) ??
+                  foo1(var7[(~(-75))], (!(false))));
+              {
+                int loc2 = 64;
+                while (--loc2 > 0) {
+                  var7 = var7;
+
+                  /// Single-line documentation comment.
+                  if (true) {
+                    par2 = (var8).add(((var7[var1] + (-(4294967425))) ??
+                        var7[((-(-9223372032559775745)) - (--var4))]));
+                    if ((Map.from(par1)).isEmpty) {
+                      var9 ??= ((Map.unmodifiable(Map.unmodifiable(par1)) ??
+                              (((var2).isInfinite ? var9 : par1) ??
+                                  Map.unmodifiable((par1 ?? par1)))) ??
+                          (Map.unmodifiable({
+                                51: par1[(~((~(Uint64List.bytesPerElement))))],
+                                14: foo0(),
+                                69: var0[var1],
+                                56: loc1,
+                                41: (false ? var0[Int32x4.yxwy] : loc1),
+                                30: ((!(var3)) ? '' : 'L'),
+                                80: 'UsR6'
+                              }) ??
+                              {
+                                67: loc1,
+                                73: ((var4).isEven
+                                    ? ('' ?? (var3 ? foo0() : var6))
+                                    : foo0())
+                              }));
+                    }
+                  } else {
+                    var7[(SecurityContext.alpnSupported
+                        ? (~((true ? Float32x4.ywzw : -97)))
+                        : loc2)] = (--var2);
+                  }
+                }
+              }
+            }
+            break;
+        }
+        print(true);
+      });
+    }
+    for (int loc0 in [
+      (++var1),
+      (var7[(~(((false ? (false && par2) : (71).isInfinite)
+              ? var7[87]
+              : -9223372028264841217)))] -
+          var7[var2]),
+      ((~((-(((true ? true : false)
+              ? var7[-78]
+              : (((false || false) ? true : (true && (false && true)))
+                  ? var2
+                  : (par2 ? -13 : 65))))))) >>
+          ((var3 ? false : false) ? (~((~(-97)))) : Uint8List.bytesPerElement))
+    ]) {
+      // Single-line comment.
+      break;
+    }
+  }
+  return 'F+\u2665';
+}
+
+main() {
+  try {
+    foo2(
+        ((var3 ? var9 : var0) ??
+            {
+              30: '',
+              58: '\u2665bc',
+              45: ' \u{1f600}',
+              79: 'zLuiBp',
+              2: 'X9\u{1f600}2Lq',
+              78: 'PP6NIH',
+              77: 'OB',
+              80: 'EcL\u{1f600}yp'
+            }),
+        (!(((47).toString()).isEmpty)));
+  } on OutOfMemoryError {
+    print('oom');
+    exit(254);
+  } catch (e, st) {
+    print('foo2 throws');
+  }
+}
diff --git a/runtime/tests/vm/dart/regress_38700_test.dart b/runtime/tests/vm/dart/regress_38700_test.dart
new file mode 100644
index 0000000..cc6c0ee
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_38700_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.
+
+import 'package:expect/expect.dart';
+
+Map<String, num> map = {'a': 1};
+
+main() {
+  var exception;
+  try {
+    print((map['b'] > 82) ? 'x' : 'y');
+  } catch (e, s) {
+    exception = e;
+  }
+  Expect.isTrue(exception is NoSuchMethodError);
+}
diff --git a/runtime/tests/vm/dart/transferable_throws_oom_test.dart b/runtime/tests/vm/dart/transferable_throws_oom_test.dart
index fcf9e08..d75c621 100644
--- a/runtime/tests/vm/dart/transferable_throws_oom_test.dart
+++ b/runtime/tests/vm/dart/transferable_throws_oom_test.dart
@@ -5,6 +5,7 @@
 // Customize ASAN options for this test with 'allocator_may_return_null=1' as
 // it tries to allocate a large memory buffer.
 // Environment=ASAN_OPTIONS=handle_segv=0:detect_stack_use_after_return=1:allocator_may_return_null=1
+// Environment=LSAN_OPTIONS=handle_segv=0:detect_stack_use_after_return=1:allocator_may_return_null=1
 // Environment=MSAN_OPTIONS=handle_segv=0:detect_stack_use_after_return=1:allocator_may_return_null=1
 
 // Test that ensures correct exception when running out of memory for
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 231005a..4810538 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -84,6 +84,8 @@
 dart/data_uri_import_test/wrongmime: Crash
 
 [ $builder_tag == obfuscated && $compiler == dartkp ]
+dart/extension_names_test: SkipByDesign # No demangling (obfuscated).
+dart/extension_unnamed_names_test: SkipByDesign # No demangling (obfuscated).
 dart/optimized_stacktrace_line_and_column_test: SkipByDesign # Looks for filenames in stacktrace output
 dart/optimized_stacktrace_line_test: SkipByDesign # Looks for filenames in stacktrace output
 dart/regress_37382_test: SkipByDesign # Matches the type arguments names
@@ -268,6 +270,7 @@
 dart/compilation_trace_test: Pass, Slow
 dart/disassemble_determinism_test: SkipSlow # Runs expensive fibonacci(32) computation in 2 subprocesses
 dart/issue_31959_31960_test: SkipSlow
+dart/print_flow_graph_determinism_test: SkipSlow
 dart/slow_path_shared_stub_test: SkipSlow # Too slow with --shared-slow-path-triggers-gc flag and not relevant outside precompiled.
 dart/spawn_infinite_loop_test: Skip # We can shutdown an isolate before it reloads.
 dart/spawn_shutdown_test: Skip # We can shutdown an isolate before it reloads.
diff --git a/runtime/tools/dartfuzz/dartfuzz.dart b/runtime/tools/dartfuzz/dartfuzz.dart
index 0064441..99f26d7 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.59';
+const String version = '1.61';
 
 // Restriction on statements and expressions.
 const int stmtDepth = 1;
@@ -62,7 +62,7 @@
 class DartApi {
   DartApi(bool ffi)
       : intLibs = [
-          if (ffi) ...[
+          if (ffi) ...const [
             DartLib('intComputation', 'VIIII'),
             DartLib('takeMaxUint16', 'VI'),
             DartLib('sumPlus42', 'VII'),
@@ -90,7 +90,7 @@
           ...DartLib.intLibs,
         ],
         doubleLibs = [
-          if (ffi) ...[
+          if (ffi) ...const [
             DartLib('times1_337Float', 'VD'),
             DartLib('sumManyDoubles', 'VDDDDDDDDDD'),
             DartLib('times1_337Double', 'VD'),
@@ -153,7 +153,7 @@
     }
     // Generate.
     emitHeader();
-    emitVarDecls(varName, globalVars);
+    emitVariableDeclarations(varName, globalVars);
     emitMethods(methodName, globalMethods, ffiStatus);
     emitClasses();
     emitMain();
@@ -165,6 +165,133 @@
     assert(localVars.isEmpty);
   }
 
+  //
+  // General Helpers.
+  //
+
+  BigInt genMask(int m) => BigInt.from(1) << m;
+  int choose(int c) => rand.nextInt(c);
+  int chooseOneUpTo(int c) => choose(c) + 1;
+  bool coinFlip() => rand.nextBool();
+  bool rollDice(int c) => (choose(c) == 0);
+  double uniform() => rand.nextDouble();
+
+  // Picks one of the given choices.
+  T oneOf<T>(List<T> choices) => choices[choose(choices.length)];
+  T oneOfSet<T>(Set<T> choices) => choices.elementAt(choose(choices.length));
+
+  //
+  // Code Structure Helpers.
+  //
+
+  void incIndent() => indent += 2;
+  void decIndent() => indent -= 2;
+
+  void emitZero() => emit('0');
+
+  void emitTryCatchFinally(Function tryBody, Function catchBody,
+      {Function finallyBody, bool catchOOM = true}) {
+    emitLn('try ', newline: false);
+    emitBraceWrapped(() => tryBody());
+    if (catchOOM) {
+      emit(' on OutOfMemoryError ');
+      emitBraceWrapped(() => emitLn("exit(${oomExitCode});", newline: false));
+    }
+    emit(' catch (e, st) ');
+    emitBraceWrapped(catchBody);
+    if (finallyBody != null) {
+      emit(' finally ');
+      emitBraceWrapped(finallyBody);
+    }
+  }
+
+  dynamic emitWrapped(List<String> pair, Function exprEmitter,
+      {bool shouldIndent = true}) {
+    assert(pair.length == 2);
+    emit(pair[0]);
+    if (shouldIndent) {
+      incIndent();
+      emitNewline();
+    }
+    final result = exprEmitter();
+    if (shouldIndent) {
+      decIndent();
+      emitNewline();
+      emitLn(pair[1], newline: false);
+    } else {
+      emit(pair[1]);
+    }
+    return result;
+  }
+
+  dynamic emitParenWrapped(Function exprEmitter,
+      {bool includeSemicolon = false}) {
+    final result =
+        emitWrapped(const ['(', ')'], exprEmitter, shouldIndent: false);
+    if (includeSemicolon) {
+      emit(';');
+    }
+    return result;
+  }
+
+  dynamic emitBraceWrapped(Function exprEmitter, {bool shouldIndent = true}) =>
+      emitWrapped(const ['{', '}'], exprEmitter, shouldIndent: shouldIndent);
+
+  dynamic emitSquareBraceWrapped(Function exprEmitter) =>
+      emitWrapped(const ['[', ']'], exprEmitter, shouldIndent: false);
+
+  dynamic emitCommaSeparated(Function(int) elementBuilder, int length,
+      {int start = 0, bool newline = false}) {
+    for (int i = start; i < length; ++i) {
+      elementBuilder(i);
+      if (i + 1 != length) {
+        emit(',', newline: newline);
+        if (!newline) {
+          emit(' ');
+        }
+      }
+    }
+  }
+
+  void emitFunctionDefinition(String name, Function body, {String retType}) {
+    emitIndentation();
+    if (retType != null) {
+      emit(retType + ' ');
+    }
+    emit(name);
+    emit('() '); // TODO(bkonyi): handle params
+
+    emitBraceWrapped(body);
+  }
+
+  bool emitIfStatement(
+      Function ifConditionEmitter, bool Function() ifBodyEmitter,
+      {bool Function() elseBodyEmitter}) {
+    emitLn('if ', newline: false);
+    emitParenWrapped(ifConditionEmitter);
+    final bool b1 = emitBraceWrapped(ifBodyEmitter);
+    bool b2 = false;
+    if (elseBodyEmitter != null) {
+      emit(' else ');
+      b2 = emitBraceWrapped(elseBodyEmitter);
+    }
+    return b1 || b2;
+  }
+
+  void emitImport(String library, {String asName}) => (asName == null)
+      ? emitLn("import '$library';")
+      : emitLn("import '$library' as $asName;");
+
+  void emitBinaryComparison(Function e1, String op, Function e2,
+      {bool includeSemicolon = false}) {
+    e1();
+    emit(' $op ');
+    e2();
+    if (includeSemicolon) {
+      emit(';');
+    }
+  }
+
   // Randomly specialize interface if possible. E.g. num to int.
   DartType maybeSpecializeInterface(DartType tp) {
     if (!dartType.isSpecializable(tp)) return tp;
@@ -211,8 +338,6 @@
     }
   }
 
-  BigInt genMask(int m) => BigInt.from(1) << m;
-
   // Process the opening of a statement.
   // Determine whether the statement should be skipped based on the
   // statement index stored in stmtCntr and the statement mask stored
@@ -308,70 +433,68 @@
   void emitHeader() {
     emitLn('// The Dart Project Fuzz Tester ($version).');
     emitLn('// Program generated as:');
-    emitLn('//   dart dartfuzz.dart --seed $seed --${fp ? "" : "no-"}fp ' +
+    emitLn('//   dart dartfuzz.dart --seed $seed --${fp ? "" : "no-"}fp '
         '--${ffi ? "" : "no-"}ffi --${flatTp ? "" : "no-"}flat');
-    emitLn('');
-    emitLn("import 'dart:async';");
-    emitLn("import 'dart:cli';");
-    emitLn("import 'dart:collection';");
-    emitLn("import 'dart:convert';");
-    emitLn("import 'dart:core';");
-    emitLn("import 'dart:io';");
-    emitLn("import 'dart:isolate';");
-    emitLn("import 'dart:math';");
-    emitLn("import 'dart:typed_data';");
+    emitNewline();
+    emitImport('dart:async');
+    emitImport('dart:cli');
+    emitImport('dart:collection');
+    emitImport('dart:convert');
+    emitImport('dart:core');
+    emitImport('dart:io');
+    emitImport('dart:isolate');
+    emitImport('dart:math');
+    emitImport('dart:typed_data');
     if (ffi) {
-      emitLn("import 'dart:ffi' as ffi;");
+      emitImport('dart:ffi', asName: 'ffi');
       emitLn(DartFuzzFfiApi.ffiapi);
     }
+    emitNewline();
   }
 
   void emitFfiCast(String dartFuncName, String ffiFuncName, String typeName,
       List<DartType> pars) {
-    emit("${pars[0].name} Function(");
-    for (int i = 1; i < pars.length; i++) {
-      DartType tp = pars[i];
-      emit('${tp.name}');
-      if (i != (pars.length - 1)) {
-        emit(', ');
-      }
-    }
-    emit(') ${dartFuncName} = ' +
-        'ffi.Pointer.fromFunction<${typeName}>(${ffiFuncName}, ');
-    emitLiteral(0, pars[0], smallPositiveValue: true);
-    emitLn(').cast<ffi.NativeFunction<${typeName}>>().asFunction();');
+    emit("${pars[0].name} Function");
+    emitParenWrapped(() => emitCommaSeparated(
+        (int i) => emit('${pars[i].name}'), pars.length,
+        start: 1));
+    emit(' ${dartFuncName} = ffi.Pointer.fromFunction<${typeName}>');
+    emitParenWrapped(() {
+      emit('${ffiFuncName}, ');
+      emitLiteral(0, pars[0], smallPositiveValue: true);
+    });
+    emit('.cast<ffi.NativeFunction<${typeName}>>().asFunction();');
+    emitNewline();
   }
 
   void emitMethod(
       String name, int index, List<DartType> method, bool isFfiMethod) {
+    final type = method[0].name;
+    final methodName = '$name${isFfiMethod ? "Ffi" : ''}$index';
     if (isFfiMethod) {
       emitFfiTypedef("${name}Ffi${index}Type", method);
-      emitLn('${method[0].name} ${name}Ffi$index(', newline: false);
-    } else {
-      emitLn('${method[0].name} $name$index(', newline: false);
     }
-    emitParDecls(method);
-    if (!isFfiMethod && rand.nextInt(10) == 0) {
+    emitLn('$type $methodName', newline: false);
+    emitParenWrapped(() => emitParDecls(method));
+    if (!isFfiMethod && rollDice(10)) {
       // Emit a method using "=>" syntax.
-      emit(') => ');
-      emitExpr(0, method[0]);
-      emit(';', newline: true);
-      return;
+      emit(' => ');
+      emitExpr(0, method[0], includeSemicolon: true);
+    } else {
+      emitBraceWrapped(() {
+        assert(localVars.isEmpty);
+        if (emitStatements(0)) {
+          emitReturn();
+        }
+        assert(localVars.isEmpty);
+      });
     }
-    emit(') {', newline: true);
-    indent += 2;
-    assert(localVars.isEmpty);
-    if (emitStatements(0)) {
-      emitReturn();
-    }
-    assert(localVars.isEmpty);
-    indent -= 2;
-    emitLn('}');
     if (isFfiMethod) {
       emitFfiCast("${name}${index}", "${name}Ffi${index}",
           "${name}Ffi${index}Type", method);
     }
-    emit('', newline: true);
+    emitNewline();
+    emitNewline();
   }
 
   void emitMethods(String name, List<List<DartType>> methods,
@@ -394,7 +517,7 @@
     while (parentClass >= 0) {
       vcm[parentClass] = <int>[];
       for (int j = 0, n = classMethods[parentClass].length; j < n; j++) {
-        if (rand.nextInt(8) == 0) {
+        if (rollDice(8)) {
           currentClass = parentClass;
           currentMethod = j;
           emitMethod('$methodName${parentClass}_', j,
@@ -404,7 +527,7 @@
           currentClass = null;
         }
       }
-      if (rand.nextInt(2) == 0 || classParents.length > parentClass) {
+      if (coinFlip() || classParents.length > parentClass) {
         break;
       } else {
         parentClass = classParents[parentClass];
@@ -419,42 +542,42 @@
     for (int i = 0; i < classFields.length; i++) {
       if (i == 0) {
         classParents.add(-1);
-        emitLn('class X0 {');
+        emit('class X0 ');
       } else {
-        final int parentClass = rand.nextInt(i);
+        final int parentClass = choose(i);
         classParents.add(parentClass);
-        if (rand.nextInt(2) != 0) {
+        if (choose(2) != 0) {
           // Inheritance
-          emitLn('class X$i extends X${parentClass} {');
+          emit('class X$i extends X${parentClass} ');
         } else {
           // Mixin
           if (classParents[parentClass] >= 0) {
-            emitLn(
-                'class X$i extends X${classParents[parentClass]} with X${parentClass} {');
+            emit(
+                'class X$i extends X${classParents[parentClass]} with X${parentClass} ');
           } else {
-            emitLn('class X$i with X${parentClass} {');
+            emit('class X$i with X${parentClass} ');
           }
         }
       }
-      indent += 2;
-      emitVarDecls('$fieldName${i}_', classFields[i]);
-      currentClass = i;
-      emitVirtualMethods();
-      emitMethods('$methodName${i}_', classMethods[i]);
-      emitLn('void run() {');
-      indent += 2;
-      if (i > 0) {
-        emitLn('super.run();');
-      }
-      assert(localVars.isEmpty);
-      emitStatements(0);
-      assert(localVars.isEmpty);
-      indent -= 2;
-      emitLn('}');
-      indent -= 2;
-      emitLn('}');
-      emit('', newline: true);
+      emitBraceWrapped(() {
+        emitVariableDeclarations('$fieldName${i}_', classFields[i]);
+        currentClass = i;
+        emitVirtualMethods();
+        emitMethods('$methodName${i}_', classMethods[i]);
+        emitFunctionDefinition('run', () {
+          if (i > 0) {
+            // FIXME(bkonyi): fix potential issue where we try to apply a class
+            // as a mixin when it calls super.
+            emitLn('super.run();');
+          }
+          assert(localVars.isEmpty);
+          emitStatements(0);
+          assert(localVars.isEmpty);
+        }, retType: 'void');
+      });
       currentClass = null;
+      emitNewline();
+      emitNewline();
     }
   }
 
@@ -467,132 +590,117 @@
           '// By not catching this exception, we terminate the program with ' +
               'a full stack trace');
       emitLn('// which, in turn, flags the problem prominently');
-      emitLn('if (ffiTestFunctions == null) {');
-      indent += 2;
-      emitLn('print(\'Did not load ffi test functions\');');
-      indent -= 2;
-      emitLn('}');
+      emitIfStatement(() => emit('ffiTestFunctions == null'),
+          () => emitPrint('Did not load ffi test functions'));
     }
   }
 
-  void emitTryCatchFinally(Function tryBody, Function catchBody,
-      {Function finallyBody}) {
-    emitLn('try {');
-    indent += 2;
-    emitLn("", newline: false);
-    tryBody();
-    emit(";", newline: true);
-    indent -= 2;
-    emitLn('} on OutOfMemoryError {');
-    indent += 2;
-    emitLn("exit(${oomExitCode});");
-    indent -= 2;
-    emitLn('} catch (e, st) {');
-    indent += 2;
-    catchBody();
-    indent -= 2;
-    if (finallyBody != null) {
-      emitLn('} finally {');
-      indent += 2;
-      finallyBody();
-      indent -= 2;
-    }
-    emitLn('}');
-  }
+  void emitMain() => emitFunctionDefinition('main', () {
+        emitLoadFfiLib();
 
-  void emitMain() {
-    emitLn('main() {');
-    indent += 2;
+        // Call each global method once.
+        for (int i = 0; i < globalMethods.length; i++) {
+          final outputName = '$methodName$i';
+          emitTryCatchFinally(() {
+            emitCall(1, outputName, globalMethods[i], includeSemicolon: true);
+          }, () {
+            emitPrint('$outputName throws');
+          });
+          emitNewline();
+        }
 
-    emitLoadFfiLib();
-
-    // Call each global method once.
-    for (int i = 0; i < globalMethods.length; i++) {
-      emitTryCatchFinally(() {
-        emitCall(1, "$methodName${i}", globalMethods[i]);
-      }, () {
-        emitLn("print('$methodName$i throws');");
-      });
-    }
-
-    // Call each class method once.
-    for (int i = 0; i < classMethods.length; i++) {
-      for (int j = 0; j < classMethods[i].length; j++) {
-        emitTryCatchFinally(() {
-          emitCall(1, "X${i}().$methodName${i}_${j}", classMethods[i][j]);
-        }, () {
-          emitLn("print('X${i}().$methodName${i}_${j}() throws');");
-        });
-      }
-      // Call each virtual class method once.
-      int parentClass = classParents[i];
-      while (parentClass >= 0) {
-        if (virtualClassMethods[i].containsKey(parentClass)) {
-          for (int j = 0; j < virtualClassMethods[i][parentClass].length; j++) {
+        // Call each class method once.
+        for (int i = 0; i < classMethods.length; i++) {
+          for (int j = 0; j < classMethods[i].length; j++) {
+            final outputName = 'X${i}().$methodName${i}_${j}';
+            emitNewline();
             emitTryCatchFinally(() {
-              emitCall(1, "X${i}().$methodName${parentClass}_${j}",
-                  classMethods[parentClass][j]);
+              emitCall(1, outputName, classMethods[i][j],
+                  includeSemicolon: true);
             }, () {
-              emitLn(
-                  "print('X${i}().$methodName${parentClass}_${j}() throws');");
+              emitPrint('$outputName() throws');
             });
           }
+          // Call each virtual class method once.
+          int parentClass = classParents[i];
+          while (parentClass >= 0) {
+            if (virtualClassMethods[i].containsKey(parentClass)) {
+              for (int j = 0;
+                  j < virtualClassMethods[i][parentClass].length;
+                  j++) {
+                final outputName = 'X${i}().$methodName${parentClass}_${j}';
+                emitNewline();
+                emitTryCatchFinally(
+                    () => emitCall(1, outputName, classMethods[parentClass][j],
+                        includeSemicolon: true),
+                    () => emitPrint('$outputName() throws'));
+              }
+            }
+            parentClass = classParents[parentClass];
+          }
         }
-        parentClass = classParents[parentClass];
-      }
-    }
 
-    emitTryCatchFinally(() {
-      emit('X${classFields.length - 1}().run()');
-    }, () {
-      emitLn("print('X${classFields.length - 1}().run() throws');");
-    });
+        emitNewline();
+        emitTryCatchFinally(() {
+          emitLn('X${classFields.length - 1}().run();', newline: false);
+        }, () {
+          emitPrint('X${classFields.length - 1}().run() throws');
+        });
 
-    emitTryCatchFinally(() {
-      emit("print('", newline: false);
-      for (int i = 0; i < globalVars.length; i++) {
-        emit('\$$varName$i\\n');
-      }
-      emit("')");
-    }, () {
-      emitLn("print('print throws');");
-    });
-
-    indent -= 2;
-    emitLn('}');
-  }
+        emitNewline();
+        emitTryCatchFinally(() {
+          String body = '';
+          for (int i = 0; i < globalVars.length; i++) {
+            body += '\$$varName$i\\n';
+          }
+          emitPrint('$body');
+        }, () => emitPrint('print throws'));
+      });
 
   //
   // Declarations.
   //
 
-  void emitVarDecls(String name, List<DartType> vars) {
-    emit('', newline: true);
+  void emitVariableDeclarations(String name, List<DartType> vars) {
     for (int i = 0; i < vars.length; i++) {
       DartType tp = vars[i];
-      emitLn('${tp.name} $name$i = ', newline: false);
-      emitConstructorOrLiteral(0, tp);
-      emit(';', newline: true);
+      final varName = '$name$i';
+      emitVariableDeclaration(varName, tp,
+          initializerEmitter: () => emitConstructorOrLiteral(0, tp));
     }
-    emit('', newline: true);
+    emitNewline();
   }
 
-  void emitParDecls(List<DartType> pars) {
-    for (int i = 1; i < pars.length; i++) {
-      DartType tp = pars[i];
-      emit('${tp.name} $paramName$i');
-      if (i != (pars.length - 1)) {
-        emit(', ');
-      }
+  void emitVariableDeclaration(String name, DartType tp,
+      {Function initializerEmitter,
+      bool indent = true,
+      bool newline = true,
+      bool includeSemicolon = true}) {
+    final typeName = tp.name;
+    if (indent) {
+      emitIndentation();
+    }
+    emit('$typeName $name', newline: false);
+    if (initializerEmitter != null) {
+      emit(' = ');
+      initializerEmitter();
+    }
+    if (includeSemicolon) {
+      emit(';', newline: newline);
     }
   }
 
+  void emitParDecls(List<DartType> pars) => emitCommaSeparated((int i) {
+        DartType tp = pars[i];
+        emit('${tp.name} $paramName$i');
+      }, pars.length, start: 1);
+
   //
   // Comments (for FE and analysis tools).
   //
 
   void emitComment() {
-    switch (rand.nextInt(4)) {
+    switch (choose(4)) {
       case 0:
         emitLn('// Single-line comment.');
         break;
@@ -636,7 +744,7 @@
         throw 'No assign operation for ${tp.name}';
       }
     }
-    emitLn('', newline: false);
+    emitIndentation();
     // Emit a variable of the lhs type.
     final emittedVar = emitVar(0, tp, isLhs: true);
     RhsFilter rhsFilter = RhsFilter.fromDartType(tp, emittedVar);
@@ -648,17 +756,21 @@
       throw 'No rhs type for assign ${tp.name} $assignOp';
     }
 
-    emitExpr(0, rhsType, rhsFilter: rhsFilter);
-    emit(';', newline: true);
+    emitExpr(0, rhsType, rhsFilter: rhsFilter, includeSemicolon: true);
     return true;
   }
 
   // Emit a print statement.
-  bool emitPrint() {
-    DartType tp = oneOfSet(dartType.allTypes);
-    emitLn('print(', newline: false);
-    emitExpr(0, tp);
-    emit(');', newline: true);
+  bool emitPrint([String body]) {
+    emitLn('print', newline: false);
+    emitParenWrapped(() {
+      if (body != null) {
+        emit("'$body'");
+      } else {
+        DartType tp = oneOfSet(dartType.allTypes);
+        emitExpr(0, tp);
+      }
+    }, includeSemicolon: true);
     return true;
   }
 
@@ -669,8 +781,7 @@
       emitLn('return;');
     } else {
       emitLn('return ', newline: false);
-      emitExpr(0, proto[0]);
-      emit(';', newline: true);
+      emitExpr(0, proto[0], includeSemicolon: true);
     }
     return false;
   }
@@ -679,66 +790,51 @@
   bool emitThrow() {
     DartType tp = oneOfSet(dartType.allTypes);
     emitLn('throw ', newline: false);
-    emitExpr(0, tp);
-    emit(';', newline: true);
+    emitExpr(0, tp, includeSemicolon: true);
     return false;
   }
 
   // Emit a one-way if statement.
-  bool emitIf1(int depth) {
-    emitLn('if (', newline: false);
-    emitExpr(0, DartType.BOOL);
-    emit(') {', newline: true);
-    indent += 2;
-    emitStatements(depth + 1);
-    indent -= 2;
-    emitLn('}');
-    return true;
-  }
+  bool emitIf1(int depth) => emitIfStatement(
+      () => emitExpr(0, DartType.BOOL), () => emitStatements(depth + 1));
 
   // Emit a two-way if statement.
-  bool emitIf2(int depth) {
-    emitLn('if (', newline: false);
-    emitExpr(0, DartType.BOOL);
-    emit(') {', newline: true);
-    indent += 2;
-    bool b1 = emitStatements(depth + 1);
-    indent -= 2;
-    emitLn('} else {');
-    indent += 2;
-    bool b2 = emitStatements(depth + 1);
-    indent -= 2;
-    emitLn('}');
-    return b1 || b2;
-  }
+  bool emitIf2(int depth) => emitIfStatement(
+      () => emitExpr(0, DartType.BOOL), () => emitStatements(depth + 1),
+      elseBodyEmitter: () => emitStatements(depth + 1));
 
   // Emit a simple increasing for-loop.
   bool emitFor(int depth) {
     // Make deep nesting of loops increasingly unlikely.
-    if (rand.nextInt(nest + 1) > nestDepth) {
+    if (choose(nest + 1) > nestDepth) {
       return emitAssign();
     }
     final int i = localVars.length;
-    emitLn('for (int $localName$i = 0; $localName$i < ', newline: false);
-    emitSmallPositiveInt();
-    emit('; $localName$i++) {', newline: true);
-    indent += 2;
-    nest++;
-    iterVars.add("$localName$i");
-    localVars.add(DartType.INT);
-    emitStatements(depth + 1);
-    localVars.removeLast();
-    iterVars.removeLast();
-    nest--;
-    indent -= 2;
-    emitLn('}');
+    emitLn('for ', newline: false);
+    emitParenWrapped(() {
+      final name = '$localName$i';
+      emitVariableDeclaration(name, DartType.INT,
+          initializerEmitter: emitZero, newline: false, indent: false);
+      emitBinaryComparison(() => emit(name), '<', emitSmallPositiveInt,
+          includeSemicolon: true);
+      emit('$name++');
+    });
+    emitBraceWrapped(() {
+      nest++;
+      iterVars.add('$localName$i');
+      localVars.add(DartType.INT);
+      emitStatements(depth + 1);
+      localVars.removeLast();
+      iterVars.removeLast();
+      nest--;
+    });
     return true;
   }
 
   // Emit a simple membership for-in-loop.
   bool emitForIn(int depth) {
     // Make deep nesting of loops increasingly unlikely.
-    if (rand.nextInt(nest + 1) > nestDepth) {
+    if (choose(nest + 1) > nestDepth) {
       return emitAssign();
     }
     final int i = localVars.length;
@@ -749,111 +845,120 @@
     if (elementType == null) {
       throw 'No element type for iteration type ${iterType.name}';
     }
-    emitLn('for (${elementType.name} $localName$i in ', newline: false);
-    localVars.add(null); // declared, but don't use
-    emitExpr(0, iterType);
-    localVars.removeLast(); // will get type
-    emit(') {', newline: true);
-    indent += 2;
-    nest++;
-    localVars.add(elementType);
-    emitStatements(depth + 1);
-    localVars.removeLast();
-    nest--;
-    indent -= 2;
-    emitLn('}');
+    emitLn('for ', newline: false);
+    emitParenWrapped(() {
+      emit('${elementType.name} $localName$i in ');
+      localVars.add(null); // declared, but don't use
+      emitExpr(0, iterType);
+      localVars.removeLast(); // will get type
+    });
+    emitBraceWrapped(() {
+      nest++;
+      localVars.add(elementType);
+      emitStatements(depth + 1);
+      localVars.removeLast();
+      nest--;
+    });
     return true;
   }
 
   // Emit a simple membership forEach loop.
   bool emitForEach(int depth) {
     // Make deep nesting of loops increasingly unlikely.
-    if (rand.nextInt(nest + 1) > nestDepth) {
+    if (choose(nest + 1) > nestDepth) {
       return emitAssign();
     }
-    final int i = localVars.length;
-    final int j = i + 1;
-    emitLn("", newline: false);
+    emitIndentation();
+
     // Select one map type to be used in forEach loop.
     final mapType = oneOfSet(dartType.mapTypes);
     final emittedVar = emitScalarVar(mapType, isLhs: false);
     iterVars.add(emittedVar);
-    emit('.forEach(($localName$i, $localName$j) {\n');
-    indent += 2;
-    final int nestTmp = nest;
-    // Reset, since forEach cannot break out of own or enclosing context.
-    nest = 0;
-    // Get the type of the map key and add it to the local variables.
-    localVars.add(dartType.indexType(mapType));
-    // Get the type of the map values and add it to the local variables.
-    localVars.add(dartType.elementType(mapType));
-    emitStatements(depth + 1);
-    localVars.removeLast();
-    localVars.removeLast();
-    nest = nestTmp;
-    indent -= 2;
-    emitLn('});');
+    emit('.forEach');
+    final i = localVars.length;
+    final j = i + 1;
+    emitParenWrapped(() {
+      emitParenWrapped(() => emit('$localName$i, $localName$j'));
+      emitBraceWrapped(() {
+        final int nestTmp = nest;
+        // Reset, since forEach cannot break out of own or enclosing context.
+        nest = 0;
+        // Get the type of the map key and add it to the local variables.
+        localVars.add(dartType.indexType(mapType));
+        // Get the type of the map values and add it to the local variables.
+        localVars.add(dartType.elementType(mapType));
+        emitStatements(depth + 1);
+        localVars.removeLast();
+        localVars.removeLast();
+        nest = nestTmp;
+      });
+    }, includeSemicolon: true);
     return true;
   }
 
   // Emit a while-loop.
   bool emitWhile(int depth) {
     // Make deep nesting of loops increasingly unlikely.
-    if (rand.nextInt(nest + 1) > nestDepth) {
+    if (choose(nest + 1) > nestDepth) {
       return emitAssign();
     }
     final int i = localVars.length;
-    emitLn('{ int $localName$i = ', newline: false);
-    emitSmallPositiveInt();
-    emit(';', newline: true);
-    indent += 2;
-    emitLn('while (--$localName$i > 0) {');
-    indent += 2;
-    nest++;
-    iterVars.add("$localName$i");
-    localVars.add(DartType.INT);
-    emitStatements(depth + 1);
-    localVars.removeLast();
-    iterVars.removeLast();
-    nest--;
-    indent -= 2;
-    emitLn('}');
-    indent -= 2;
-    emitLn('}');
+    emitIndentation();
+    emitBraceWrapped(() {
+      final name = '$localName$i';
+      emitVariableDeclaration(name, DartType.INT,
+          initializerEmitter: () => emitSmallPositiveInt());
+      emitLn('while ', newline: false);
+      emitParenWrapped(
+          () => emitBinaryComparison(() => emit('--$name'), '>', emitZero));
+      emitBraceWrapped(() {
+        nest++;
+        iterVars.add(name);
+        localVars.add(DartType.INT);
+        emitStatements(depth + 1);
+        localVars.removeLast();
+        iterVars.removeLast();
+        nest--;
+      });
+    });
     return true;
   }
 
   // Emit a do-while-loop.
   bool emitDoWhile(int depth) {
     // Make deep nesting of loops increasingly unlikely.
-    if (rand.nextInt(nest + 1) > nestDepth) {
+    if (choose(nest + 1) > nestDepth) {
       return emitAssign();
     }
     final int i = localVars.length;
-    emitLn('{ int $localName$i = 0;');
-    indent += 2;
-    emitLn('do {');
-    indent += 2;
-    nest++;
-    iterVars.add("$localName$i");
-    localVars.add(DartType.INT);
-    emitStatements(depth + 1);
-    localVars.removeLast();
-    iterVars.removeLast();
-    nest--;
-    indent -= 2;
-    emitLn('} while (++$localName$i < ', newline: false);
-    emitSmallPositiveInt();
-    emit(');', newline: true);
-    indent -= 2;
-    emitLn('}');
+    emitIndentation();
+    emitBraceWrapped(() {
+      final name = '$localName$i';
+      emitVariableDeclaration(name, DartType.INT, initializerEmitter: emitZero);
+      emitLn('do ', newline: false);
+      emitBraceWrapped(() {
+        nest++;
+        iterVars.add(name);
+        localVars.add(DartType.INT);
+        emitStatements(depth + 1);
+        localVars.removeLast();
+        iterVars.removeLast();
+        nest--;
+      });
+      emit(' while ');
+      emitParenWrapped(
+          () => emitBinaryComparison(
+              () => emit('++$name'), '<', emitSmallPositiveInt),
+          includeSemicolon: true);
+    });
+    emitNewline();
     return true;
   }
 
   // Emit a break/continue when inside iteration.
   bool emitBreakOrContinue(int depth) {
     if (nest > 0) {
-      switch (rand.nextInt(2)) {
+      switch (choose(2)) {
         case 0:
           emitLn('continue;');
           return false;
@@ -867,79 +972,82 @@
 
   // Emit a switch statement.
   bool emitSwitch(int depth) {
-    emitLn('switch (', newline: false);
-    emitExpr(0, DartType.INT);
-    emit(') {', newline: true);
-    int start = rand.nextInt(1 << 32);
-    int step = 1 + rand.nextInt(10);
-    for (int i = 0; i < 2; i++, start += step) {
-      indent += 2;
-      if (i == 2) {
-        emitLn('default: {');
+    emitCase(Function bodyEmitter, {int kase}) {
+      if (kase == null) {
+        emitLn('default: ', newline: false);
       } else {
-        emitLn('case $start: {');
+        emitLn('case $kase: ', newline: false);
       }
-      indent += 2;
-      emitStatements(depth + 1);
-      indent -= 2;
-      emitLn('}');
-      emitLn('break;'); // always generate, avoid FE complaints
-      indent -= 2;
+      emitBraceWrapped(() {
+        bodyEmitter();
+        emitNewline();
+        emitLn('break;',
+            newline: false); // always generate, avoid FE complaints
+      });
     }
-    emitLn('}');
+
+    emitLn('switch ', newline: false);
+    emitParenWrapped(() => emitExpr(0, DartType.INT));
+    emitBraceWrapped(() {
+      int start = choose(1 << 32);
+      int step = chooseOneUpTo(10);
+      final maxCases = 3;
+      for (int i = 0; i < maxCases; i++, start += step) {
+        emitCase(() => emitStatement(depth + 1),
+            kase: (i == 2 && coinFlip()) ? null : start);
+        if (i + 1 != maxCases) {
+          emitNewline();
+        }
+      }
+    });
     return true;
   }
 
   // Emit a new program scope that introduces a new local variable.
   bool emitScope(int depth) {
-    DartType tp = oneOfSet(dartType.allTypes);
-    final int i = localVars.length;
-    emitLn('{ ${tp.name} $localName$i = ', newline: false);
-    localVars.add(null); // declared, but don't use
-    emitExpr(0, tp);
-    localVars.removeLast(); // will get type
-    emit(';', newline: true);
-    indent += 2;
-    localVars.add(tp);
-    emitStatements(depth + 1);
-    localVars.removeLast();
-    indent -= 2;
-    emitLn('}');
+    emitIndentation();
+    emitBraceWrapped(() {
+      DartType tp = oneOfSet(dartType.allTypes);
+      final int i = localVars.length;
+      final name = '$localName$i';
+      emitVariableDeclaration(name, tp, initializerEmitter: () {
+        localVars.add(null); // declared, but don't use
+        emitExpr(0, tp);
+        localVars.removeLast(); // will get type
+      });
+      localVars.add(tp);
+      emitStatements(depth + 1);
+      localVars.removeLast();
+    });
     return true;
   }
 
   // Emit try/catch/finally.
   bool emitTryCatch(int depth) {
-    emitLn('try {');
-    indent += 2;
-    emitStatements(depth + 1);
-    indent -= 2;
-    emitLn('} catch (exception, stackTrace) {');
-    indent += 2;
-    emitStatements(depth + 1);
-    indent -= 2;
-    if (rand.nextInt(2) == 0) {
-      emitLn('} finally {');
-      indent += 2;
-      emitStatements(depth + 1);
-      indent -= 2;
+    final emitStatementsClosure = () => emitStatements(depth + 1);
+    emitLn('try ', newline: false);
+    emitBraceWrapped(emitStatementsClosure);
+    emit(' catch (exception, stackTrace) ', newline: false);
+    emitBraceWrapped(emitStatementsClosure);
+    if (coinFlip()) {
+      emit(' finally ', newline: false);
+      emitBraceWrapped(emitStatementsClosure);
     }
-    emitLn('}');
     return true;
   }
 
   // Emit a single statement.
   bool emitSingleStatement(int depth) {
     // Throw in a comment every once in a while.
-    if (rand.nextInt(10) == 0) {
+    if (rollDice(10)) {
       emitComment();
     }
     // Continuing nested statements becomes less likely as the depth grows.
-    if (rand.nextInt(depth + 1) > stmtDepth) {
+    if (choose(depth + 1) > stmtDepth) {
       return emitAssign();
     }
     // Possibly nested statement.
-    switch (rand.nextInt(16)) {
+    switch (choose(16)) {
       // Favors assignment.
       case 0:
         return emitPrint();
@@ -986,11 +1094,14 @@
 
   // Emit statements. Returns true if code may fall-through.
   bool emitStatements(int depth) {
-    int s = 1 + rand.nextInt(numStatements);
+    int s = chooseOneUpTo(numStatements);
     for (int i = 0; i < s; i++) {
       if (!emitStatement(depth)) {
         return false; // rest would be dead code
       }
+      if (i + 1 != s) {
+        emitNewline();
+      }
     }
     return true;
   }
@@ -999,20 +1110,19 @@
   // Expressions.
   //
 
-  void emitBool() {
-    emit(rand.nextInt(2) == 0 ? 'true' : 'false');
+  void emitBool() => emit(coinFlip() ? 'true' : 'false');
+
+  void emitSmallPositiveInt({int limit = 50, bool includeSemicolon = false}) {
+    emit('${choose(limit)}');
+    if (includeSemicolon) {
+      emit(';');
+    }
   }
 
-  void emitSmallPositiveInt({int limit = 50}) {
-    emit('${rand.nextInt(limit)}');
-  }
-
-  void emitSmallNegativeInt() {
-    emit('-${rand.nextInt(100)}');
-  }
+  void emitSmallNegativeInt() => emit('-${choose(100)}');
 
   void emitInt() {
-    switch (rand.nextInt(7)) {
+    switch (choose(7)) {
       // Favors small ints.
       case 0:
       case 1:
@@ -1030,12 +1140,10 @@
     }
   }
 
-  void emitDouble() {
-    emit('${rand.nextDouble()}');
-  }
+  void emitDouble() => emit('${uniform()}');
 
   void emitNum({bool smallPositiveValue = false}) {
-    if (!fp || rand.nextInt(2) == 0) {
+    if (!fp || coinFlip()) {
       if (smallPositiveValue) {
         emitSmallPositiveInt();
       } else {
@@ -1047,20 +1155,21 @@
   }
 
   void emitChar() {
-    switch (rand.nextInt(10)) {
+    switch (choose(10)) {
       // Favors regular char.
       case 0:
         emit(oneOf(interestingChars));
         break;
       default:
-        emit(regularChars[rand.nextInt(regularChars.length)]);
+        emit(regularChars[choose(regularChars.length)]);
         break;
     }
   }
 
   void emitString({int length = 8}) {
+    final n = choose(length);
     emit("'");
-    for (int i = 0, n = rand.nextInt(length); i < n; i++) {
+    for (int i = 0; i < n; i++) {
       emitChar();
     }
     emit("'");
@@ -1084,6 +1193,7 @@
     if (DartType.isMapType(tp)) {
       // Emit construct for the map key type.
       final indexType = dartType.indexType(tp);
+      emitIndentation();
       emitElementExpr(depth, indexType, rhsFilter: rhsFilter);
       emit(' : ');
       // Emit construct for the map value type.
@@ -1095,7 +1205,7 @@
   }
 
   void emitCollectionElement(int depth, DartType tp, {RhsFilter rhsFilter}) {
-    int r = depth <= exprDepth ? rand.nextInt(10) : 10;
+    int r = (depth <= exprDepth) ? choose(10) : 10;
     // TODO (felih): disable complex collection constructs for new types for
     // now.
     if (!{DartType.MAP_INT_STRING, DartType.LIST_INT, DartType.SET_INT}
@@ -1108,19 +1218,20 @@
       case 0:
         // TODO (ajcbik): Remove restriction once compiler is fixed.
         if (depth < 2) {
-          emit('...'); // spread
+          emitLn('...', newline: false); // spread
           emitCollection(depth + 1, tp, rhsFilter: rhsFilter);
         } else {
           emitElement(depth, tp, rhsFilter: rhsFilter);
         }
         break;
       case 1:
-        emit('if (');
-        emitElementExpr(depth + 1, DartType.BOOL, rhsFilter: rhsFilter);
-        emit(') ');
+        emitLn('if ', newline: false);
+        emitParenWrapped(() =>
+            emitElementExpr(depth + 1, DartType.BOOL, rhsFilter: rhsFilter));
         emitCollectionElement(depth + 1, tp, rhsFilter: rhsFilter);
-        if (rand.nextBool()) {
-          emit(' else ');
+        if (coinFlip()) {
+          emitNewline();
+          emitLn('else ', newline: false);
           emitCollectionElement(depth + 1, tp, rhsFilter: rhsFilter);
         }
         break;
@@ -1129,31 +1240,41 @@
           final int i = localVars.length;
           // TODO (felih): update to use new type system. Add types like
           // LIST_STRING etc.
-          emit('for (int $localName$i ');
-          // For-loop (induction, list, set).
-          localVars.add(null); // declared, but don't use
-          switch (rand.nextInt(3)) {
-            case 0:
-              emit('= 0; $localName$i < ');
-              emitSmallPositiveInt(limit: 16);
-              emit('; $localName$i++) ');
-              break;
-            case 1:
-              emit('in ');
-              emitCollection(depth + 1, DartType.LIST_INT,
-                  rhsFilter: rhsFilter);
-              emit(') ');
-              break;
-            default:
-              emit('in ');
-              emitCollection(depth + 1, DartType.SET_INT, rhsFilter: rhsFilter);
-              emit(') ');
-              break;
-          }
-          localVars.removeLast(); // will get type
+          emitLn('for ', newline: false);
+          emitParenWrapped(() {
+            final local = '$localName$i';
+            iterVars.add(local);
+            // For-loop (induction, list, set).
+            localVars.add(null); // declared, but don't use
+            switch (choose(3)) {
+              case 0:
+                emitVariableDeclaration(local, DartType.INT,
+                    initializerEmitter: emitZero, indent: false);
+                emitBinaryComparison(() => emit(local), '<',
+                    () => emitSmallPositiveInt(limit: 16),
+                    includeSemicolon: true);
+                emit('$local++');
+                break;
+              case 1:
+                emitVariableDeclaration(local, DartType.INT,
+                    includeSemicolon: false, indent: false);
+                emit(' in ');
+                emitCollection(depth + 1, DartType.LIST_INT,
+                    rhsFilter: rhsFilter);
+                break;
+              default:
+                emitVariableDeclaration(local, DartType.INT,
+                    includeSemicolon: false, indent: false);
+                emit(' in ');
+                emitCollection(depth + 1, DartType.SET_INT,
+                    rhsFilter: rhsFilter);
+                break;
+            }
+            localVars.removeLast(); // will get type
+          });
           nest++;
-          iterVars.add("$localName$i");
           localVars.add(DartType.INT);
+          emitNewline();
           emitCollectionElement(depth + 1, tp, rhsFilter: rhsFilter);
           localVars.removeLast();
           iterVars.removeLast();
@@ -1166,18 +1287,16 @@
     }
   }
 
-  void emitCollection(int depth, DartType tp, {RhsFilter rhsFilter}) {
-    // Collection length decreases as depth increases.
-    int collectionLength = max(1, 8 - depth);
-    emit(DartType.isListType(tp) ? '[ ' : '{ ');
-    for (int i = 0, n = 1 + rand.nextInt(collectionLength); i < n; i++) {
-      emitCollectionElement(depth, tp, rhsFilter: rhsFilter);
-      if (i != (n - 1)) {
-        emit(', ');
-      }
-    }
-    emit(DartType.isListType(tp) ? ' ]' : ' }');
-  }
+  void emitCollection(int depth, DartType tp, {RhsFilter rhsFilter}) =>
+      emitWrapped(DartType.isListType(tp) ? const ['[', ']'] : const ['{', '}'],
+          () {
+        // Collection length decreases as depth increases.
+        int collectionLength = max(1, 8 - depth);
+        emitCommaSeparated(
+            (int _) => emitCollectionElement(depth, tp, rhsFilter: rhsFilter),
+            chooseOneUpTo(collectionLength),
+            newline: DartType.isMapType(tp));
+      }, shouldIndent: DartType.isMapType(tp));
 
   void emitLiteral(int depth, DartType tp,
       {bool smallPositiveValue = false, RhsFilter rhsFilter}) {
@@ -1215,7 +1334,8 @@
 
   // Emit a constructor for a type, this can either be a trivial constructor
   // (i.e. parsed from a literal) or an actual function invocation.
-  void emitConstructorOrLiteral(int depth, DartType tp, {RhsFilter rhsFilter}) {
+  void emitConstructorOrLiteral(int depth, DartType tp,
+      {RhsFilter rhsFilter, bool includeSemicolon = false}) {
     // If there is at least one non trivial constructor for the type tp
     // select one of these constructors.
     if (dartType.hasConstructor(tp)) {
@@ -1224,34 +1344,35 @@
       // constructors (e.g. X.fromList(...) and new X(...) respectively).
       // Empty constructors are invoked with new + type name, non-empty
       // constructors are static functions of the type.
-      if (!constructor.isEmpty) {
-        emit('${tp.name}');
-        emit('.${constructor}');
+      if (constructor.isNotEmpty) {
+        emit('${tp.name}.${constructor}');
       } else {
-        emit('new ${tp.name}');
+        // New is no longer necessary as of Dart 2, but is still supported.
+        // Emit a `new` once in a while to ensure it's covered.
+        emit('${rollDice(10) ? "new " : ""}${tp.name}');
       }
-      emit('(');
-      // Iterate over constructor parameters.
-      List<DartType> constructorParameters =
-          dartType.constructorParameters(tp, constructor);
-      if (constructorParameters == null) {
-        throw 'No constructor parameters for ${tp.name}.$constructor';
-      }
-      for (int i = 0, n = constructorParameters.length; i < n; ++i) {
-        // If we are emitting a constructor parameter, we want to use small
-        // values to avoid programs that run out of memory.
-        // TODO (felih): maybe allow occasionally?
-        emitLiteral(depth + 1, constructorParameters[i],
-            smallPositiveValue: true, rhsFilter: rhsFilter);
-        if (i != n - 1) {
-          emit(", ");
+      emitParenWrapped(() {
+        // Iterate over constructor parameters.
+        List<DartType> constructorParameters =
+            dartType.constructorParameters(tp, constructor);
+        if (constructorParameters == null) {
+          throw 'No constructor parameters for ${tp.name}.$constructor';
         }
-      }
-      emit(')');
+        emitCommaSeparated((int i) {
+          // If we are emitting a constructor parameter, we want to use small
+          // values to avoid programs that run out of memory.
+          // TODO (felih): maybe allow occasionally?
+          emitLiteral(depth + 1, constructorParameters[i],
+              smallPositiveValue: true, rhsFilter: rhsFilter);
+        }, constructorParameters.length);
+      });
     } else {
       // Otherwise type can be constructed from a literal.
       emitLiteral(depth + 1, tp, rhsFilter: rhsFilter);
     }
+    if (includeSemicolon) {
+      emit(';');
+    }
   }
 
   String emitScalarVar(DartType tp, {bool isLhs = false, RhsFilter rhsFilter}) {
@@ -1280,7 +1401,7 @@
     // Make modification of the iteration variable from the loop
     // body less likely.
     if (isLhs) {
-      if (rand.nextInt(100) != 0) {
+      if (!rollDice(100)) {
         Set<String> cleanChoices = choices.difference(Set.from(iterVars));
         if (cleanChoices.isNotEmpty) {
           choices = cleanChoices;
@@ -1307,7 +1428,7 @@
     if (choices.isEmpty) {
       throw 'No variable to emit for type ${tp.name}';
     }
-    final emittedVar = '${choices.elementAt(rand.nextInt(choices.length))}';
+    final emittedVar = '${choices.elementAt(choose(choices.length))}';
     if (rhsFilter != null && (emittedVar == rhsFilter.lhsVar)) {
       rhsFilter.consume();
     }
@@ -1326,10 +1447,9 @@
       final indexType = dartType.indexType(iterType);
       // Emit a variable of the selected list or map type.
       ret = emitScalarVar(iterType, isLhs: isLhs, rhsFilter: rhsFilter);
-      emit('[');
-      // Emit an expression resolving into the index type.
-      emitExpr(depth + 1, indexType);
-      emit(']');
+      emitSquareBraceWrapped(() =>
+          // Emit an expression resolving into the index type.
+          emitExpr(depth + 1, indexType));
     } else {
       ret = emitScalarVar(tp,
           isLhs: isLhs, rhsFilter: rhsFilter); // resort to scalar
@@ -1339,7 +1459,7 @@
 
   String emitVar(int depth, DartType tp,
       {bool isLhs = false, RhsFilter rhsFilter}) {
-    switch (rand.nextInt(2)) {
+    switch (choose(2)) {
       case 0:
         return emitScalarVar(tp, isLhs: isLhs, rhsFilter: rhsFilter);
         break;
@@ -1351,7 +1471,7 @@
   }
 
   void emitTerminal(int depth, DartType tp, {RhsFilter rhsFilter}) {
-    switch (rand.nextInt(2)) {
+    switch (choose(2)) {
       case 0:
         emitLiteral(depth, tp, rhsFilter: rhsFilter);
         break;
@@ -1361,27 +1481,22 @@
     }
   }
 
-  void emitExprList(int depth, List<DartType> proto, {RhsFilter rhsFilter}) {
-    emit('(');
-    for (int i = 1; i < proto.length; i++) {
-      emitExpr(depth, proto[i], rhsFilter: rhsFilter);
-      if (i != (proto.length - 1)) {
-        emit(', ');
-      }
-    }
-    emit(')');
-  }
+  void emitExprList(int depth, List<DartType> proto, {RhsFilter rhsFilter}) =>
+      emitParenWrapped(() {
+        emitCommaSeparated((int i) {
+          emitExpr(depth, proto[i], rhsFilter: rhsFilter);
+        }, proto.length, start: 1);
+      });
 
   // Emit expression with unary operator: (~(x))
   void emitUnaryExpr(int depth, DartType tp, {RhsFilter rhsFilter}) {
     if (dartType.uniOps(tp).isEmpty) {
       return emitTerminal(depth, tp, rhsFilter: rhsFilter);
     }
-    emit('(');
-    emit(oneOfSet(dartType.uniOps(tp)));
-    emit('(');
-    emitExpr(depth + 1, tp, rhsFilter: rhsFilter);
-    emit('))');
+    emitParenWrapped(() {
+      emit(oneOfSet(dartType.uniOps(tp)));
+      emitParenWrapped(() => emitExpr(depth + 1, tp, rhsFilter: rhsFilter));
+    });
   }
 
   // Emit expression with binary operator: (x + y)
@@ -1403,48 +1518,51 @@
     if (binop == "*" &&
         DartType.isGrowableType(binOpParams[0]) &&
         dartType.isInterfaceOfType(binOpParams[1], DartType.NUM)) {
-      emit('(');
-      emitExpr(depth + 1, binOpParams[0], rhsFilter: rhsFilter);
-      emit(' $binop ');
-      emitLiteral(depth + 1, binOpParams[1], smallPositiveValue: true);
-      emit(')');
+      emitParenWrapped(() {
+        emitExpr(depth + 1, binOpParams[0], rhsFilter: rhsFilter);
+        emit(' $binop ');
+        emitLiteral(depth + 1, binOpParams[1], smallPositiveValue: true);
+      });
     } else if (binop == "*" &&
         DartType.isGrowableType(binOpParams[1]) &&
         dartType.isInterfaceOfType(binOpParams[0], DartType.NUM)) {
-      emit('(');
-      emitLiteral(depth + 1, binOpParams[0], smallPositiveValue: true);
-      emit(' $binop ');
-      emitExpr(depth + 1, binOpParams[1], rhsFilter: rhsFilter);
-      emit(')');
+      emitParenWrapped(() {
+        emitLiteral(depth + 1, binOpParams[0], smallPositiveValue: true);
+        emit(' $binop ');
+        emitExpr(depth + 1, binOpParams[1], rhsFilter: rhsFilter);
+      });
     } else {
-      emit('(');
-      emitExpr(depth + 1, binOpParams[0], rhsFilter: rhsFilter);
-      emit(' $binop ');
-      emitExpr(depth + 1, binOpParams[1], rhsFilter: rhsFilter);
-      emit(')');
+      emitParenWrapped(() {
+        emitExpr(depth + 1, binOpParams[0], rhsFilter: rhsFilter);
+        emit(' $binop ');
+        emitExpr(depth + 1, binOpParams[1], rhsFilter: rhsFilter);
+      });
     }
   }
 
   // Emit expression with ternary operator: (b ? x : y)
-  void emitTernaryExpr(int depth, DartType tp, {RhsFilter rhsFilter}) {
-    emit('(');
-    emitExpr(depth + 1, DartType.BOOL, rhsFilter: rhsFilter);
-    emit(' ? ');
-    emitExpr(depth + 1, tp, rhsFilter: rhsFilter);
-    emit(' : ');
-    emitExpr(depth + 1, tp, rhsFilter: rhsFilter);
-    emit(')');
-  }
+  void emitTernaryExpr(int depth, DartType tp, {RhsFilter rhsFilter}) =>
+      emitParenWrapped(() {
+        emitExpr(depth + 1, DartType.BOOL, rhsFilter: rhsFilter);
+        emit(' ? ');
+        emitExpr(depth + 1, tp, rhsFilter: rhsFilter);
+        emit(' : ');
+        emitExpr(depth + 1, tp, rhsFilter: rhsFilter);
+      });
 
   // Emit expression with pre/post-increment/decrement operator: (x++)
   void emitPreOrPostExpr(int depth, DartType tp, {RhsFilter rhsFilter}) {
     if (tp == DartType.INT) {
-      int r = rand.nextInt(2);
-      emit('(');
-      if (r == 0) emitPreOrPostOp(tp);
-      emitScalarVar(tp, isLhs: true);
-      if (r == 1) emitPreOrPostOp(tp);
-      emit(')');
+      emitParenWrapped(() {
+        bool pre = coinFlip();
+        if (pre) {
+          emitPreOrPostOp(tp);
+        }
+        emitScalarVar(tp, isLhs: true);
+        if (!pre) {
+          emitPreOrPostOp(tp);
+        }
+      });
     } else {
       emitTerminal(depth, tp, rhsFilter: rhsFilter); // resort to terminal
     }
@@ -1458,41 +1576,42 @@
       emitLiteral(depth + 1, tp, rhsFilter: rhsFilter);
       return;
     }
-    emit('(');
-    String proto = lib.proto;
-    // Receiver.
-    if (proto[0] != 'V') {
-      emit('(');
-      emitArg(depth + 1, proto[0], rhsFilter: rhsFilter);
-      emit(').');
-    }
-    // Call.
-    emit('${lib.name}');
-    // Parameters.
-    if (proto[1] != 'v') {
-      emit('(');
-      if (proto[1] != 'V') {
-        for (int i = 1; i < proto.length; i++) {
-          emitArg(depth + 1, proto[i], rhsFilter: rhsFilter);
-          if (i != (proto.length - 1)) {
-            emit(', ');
-          }
-        }
+    emitParenWrapped(() {
+      String proto = lib.proto;
+      // Receiver.
+      if (proto[0] != 'V') {
+        emitParenWrapped(
+            () => emitArg(depth + 1, proto[0], rhsFilter: rhsFilter));
+        emit('.');
       }
-      emit(')');
-    }
-    // Add cast to avoid error of double or int being interpreted as num.
-    if (dartType.isInterfaceOfType(tp, DartType.NUM)) {
-      emit(' as ${tp.name}');
-    }
-    emit(')');
+      // Call.
+      emit('${lib.name}');
+      // Parameters.
+      if (proto[1] != 'v') {
+        emitParenWrapped(() {
+          if (proto[1] != 'V') {
+            emitCommaSeparated(
+                (int i) => emitArg(depth + 1, proto[i], rhsFilter: rhsFilter),
+                proto.length,
+                start: 1);
+          }
+        });
+      }
+      // Add cast to avoid error of double or int being interpreted as num.
+      if (dartType.isInterfaceOfType(tp, DartType.NUM)) {
+        emit(' as ${tp.name}');
+      }
+    });
   }
 
   // Emit call to a specific method.
   void emitCall(int depth, String name, List<DartType> proto,
-      {RhsFilter rhsFilter}) {
-    emit(name);
+      {RhsFilter rhsFilter, bool includeSemicolon = false}) {
+    emitLn(name, newline: false);
     emitExprList(depth + 1, proto, rhsFilter: rhsFilter);
+    if (includeSemicolon) {
+      emit(';');
+    }
   }
 
   // Helper for a method call.
@@ -1522,7 +1641,7 @@
       int classIndex = currentClass;
       // Chase randomly up in class hierarchy.
       while (classParents[classIndex] > 0) {
-        if (rand.nextInt(2) == 0) {
+        if (coinFlip()) {
           break;
         }
         classIndex = classParents[classIndex];
@@ -1552,14 +1671,15 @@
   }
 
   // Emit expression.
-  void emitExpr(int depth, DartType tp, {RhsFilter rhsFilter}) {
+  void emitExpr(int depth, DartType tp,
+      {RhsFilter rhsFilter, bool includeSemicolon = false}) {
     final resetExprStmt = processExprOpen(tp);
     // Continuing nested expressions becomes less likely as the depth grows.
-    if (rand.nextInt(depth + 1) > exprDepth) {
+    if (choose(depth + 1) > exprDepth) {
       emitTerminal(depth, tp, rhsFilter: rhsFilter);
     } else {
       // Possibly nested expression.
-      switch (rand.nextInt(7)) {
+      switch (choose(7)) {
         case 0:
           emitUnaryExpr(depth, tp, rhsFilter: rhsFilter);
           break;
@@ -1585,6 +1705,9 @@
       }
     }
     processExprClose(resetExprStmt);
+    if (includeSemicolon) {
+      emit(';');
+    }
   }
 
   //
@@ -1593,11 +1716,8 @@
 
   // Emit same type in-out increment operator.
   void emitPreOrPostOp(DartType tp) {
-    if (tp == DartType.INT) {
-      emit(oneOf(const <String>['++', '--']));
-    } else {
-      assert(false);
-    }
+    assert(tp == DartType.INT);
+    emit(oneOf(const <String>['++', '--']));
   }
 
   // Emit one type in, boolean out operator.
@@ -1672,9 +1792,10 @@
   //
   // Types.
   //
+
   List<DartType> fillTypes1({int limit = 4, bool isFfi = false}) {
     final list = <DartType>[];
-    for (int i = 0, n = 1 + rand.nextInt(limit); i < n; i++) {
+    for (int i = 0, n = chooseOneUpTo(limit); i < n; i++) {
       if (isFfi) {
         list.add(fp ? oneOf([DartType.INT, DartType.DOUBLE]) : DartType.INT);
       } else {
@@ -1687,7 +1808,7 @@
   List<List<DartType>> fillTypes2(
       {bool isFfi = false, int limit2 = 4, int limit1 = 4}) {
     final list = <List<DartType>>[];
-    for (int i = 0, n = 1 + rand.nextInt(limit2); i < n; i++) {
+    for (int i = 0, n = chooseOneUpTo(limit2); i < n; i++) {
       list.add(fillTypes1(limit: limit1, isFfi: isFfi));
     }
     return list;
@@ -1722,9 +1843,10 @@
 
   void emitFfiType(DartType tp) {
     if (tp == DartType.INT) {
-      emit(oneOf(['ffi.Int8', 'ffi.Int16', 'ffi.Int32', 'ffi.Int64']));
+      emit(oneOf(
+          const <String>['ffi.Int8', 'ffi.Int16', 'ffi.Int32', 'ffi.Int64']));
     } else if (tp == DartType.DOUBLE) {
-      emit(oneOf(['ffi.Float', 'ffi.Double']));
+      emit(oneOf(const <String>['ffi.Float', 'ffi.Double']));
     } else {
       throw 'Invalid FFI type ${tp.name}';
     }
@@ -1733,24 +1855,28 @@
   void emitFfiTypedef(String typeName, List<DartType> pars) {
     emit("typedef ${typeName} = ");
     emitFfiType(pars[0]);
-    emit(" Function(");
-    for (int i = 1; i < pars.length; i++) {
-      DartType tp = pars[i];
-      emitFfiType(tp);
-      if (i != (pars.length - 1)) {
-        emit(', ');
-      }
-    }
-    emitLn(');');
+    emit(' Function');
+    emitParenWrapped(
+        () => emitCommaSeparated((int i) => emitFfiType(pars[i]), pars.length,
+            start: 1),
+        includeSemicolon: true);
+    emitNewline();
+    emitNewline();
   }
 
   //
   // Output.
   //
 
+  // Emits a newline to the program.
+  void emitNewline() => emit('', newline: true);
+
+  // Emits indentation based on the current indentation count.
+  void emitIndentation() => file.writeStringSync(' ' * indent);
+
   // Emits indented line to append to program.
   void emitLn(String line, {bool newline = true}) {
-    file.writeStringSync(' ' * indent);
+    emitIndentation();
     emit(line, newline: newline);
   }
 
@@ -1765,15 +1891,6 @@
     }
   }
 
-  // Emits one of the given choices.
-  T oneOf<T>(List<T> choices) {
-    return choices[rand.nextInt(choices.length)];
-  }
-
-  T oneOfSet<T>(Set<T> choices) {
-    return choices.elementAt(rand.nextInt(choices.length));
-  }
-
   // Special return code to handle oom errors.
   static const oomExitCode = 254;
 
@@ -1899,7 +2016,7 @@
 int getSeed(String userSeed) {
   int seed = int.parse(userSeed);
   if (seed == 0) {
-    Random rand = Random();
+    final rand = Random();
     while (seed == 0) {
       seed = rand.nextInt(1 << 32);
     }
@@ -1909,35 +2026,42 @@
 
 /// Main driver when dartfuzz.dart is run stand-alone.
 main(List<String> arguments) {
+  const kSeed = 'seed';
+  const kFp = 'fp';
+  const kFfi = 'ffi';
+  const kFlat = 'flat';
+  const kMini = 'mini';
+  const kSMask = 'smask';
+  const kEMask = 'emask';
   final parser = ArgParser()
-    ..addOption('seed',
+    ..addOption(kSeed,
         help: 'random seed (0 forces time-based seed)', defaultsTo: '0')
-    ..addFlag('fp', help: 'enables floating-point operations', defaultsTo: true)
-    ..addFlag('ffi',
+    ..addFlag(kFp, help: 'enables floating-point operations', defaultsTo: true)
+    ..addFlag(kFfi,
         help: 'enables FFI method calls (default: off)', defaultsTo: false)
-    ..addFlag('flat',
+    ..addFlag(kFlat,
         help: 'enables flat types (default: off)', defaultsTo: false)
     // Minimization mode extensions.
-    ..addFlag('mini',
+    ..addFlag(kMini,
         help: 'enables minimization mode (default: off)', defaultsTo: false)
-    ..addOption('smask',
+    ..addOption(kSMask,
         help: 'Bitmask indicating which statements to omit'
             '(Bit=1 omits)',
         defaultsTo: '0')
-    ..addOption('emask',
+    ..addOption(kEMask,
         help: 'Bitmask indicating which expressions to omit'
             '(Bit=1 omits)',
         defaultsTo: '0');
   try {
     final results = parser.parse(arguments);
-    final seed = getSeed(results['seed']);
-    final fp = results['fp'];
-    final ffi = results['ffi'];
-    final flatTp = results['flat'];
+    final seed = getSeed(results[kSeed]);
+    final fp = results[kFp];
+    final ffi = results[kFfi];
+    final flatTp = results[kFlat];
     final file = File(results.rest.single).openSync(mode: FileMode.write);
-    final minimize = results['mini'];
-    final smask = BigInt.parse(results['smask']);
-    final emask = BigInt.parse(results['emask']);
+    final minimize = results[kMini];
+    final smask = BigInt.parse(results[kSMask]);
+    final emask = BigInt.parse(results[kEMask]);
     final dartFuzz = DartFuzz(seed, fp, ffi, flatTp, file,
         minimize: minimize, smask: smask, emask: emask);
     dartFuzz.run();
diff --git a/runtime/tools/ffi/sdk_lib_ffi_generator.dart b/runtime/tools/ffi/sdk_lib_ffi_generator.dart
new file mode 100644
index 0000000..d0b10d2
--- /dev/null
+++ b/runtime/tools/ffi/sdk_lib_ffi_generator.dart
@@ -0,0 +1,300 @@
+// 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 file generates the extension methods public API and the extension
+// methods patch file for all integers, double, and float.
+// The PointerPointer and PointerStruct extension are written by hand since
+// those are not repetitive.
+
+import 'dart:io';
+
+import 'package:args/args.dart';
+
+//
+// Configuration.
+//
+
+const configuration = [
+  Config("Int8", "int", "Int8List", 1),
+  Config("Int16", "int", "Int16List", 2),
+  Config("Int32", "int", "Int32List", 4),
+  Config("Int64", "int", "Int64List", 8),
+  Config("Uint8", "int", "Uint8List", 1),
+  Config("Uint16", "int", "Uint16List", 2),
+  Config("Uint32", "int", "Uint32List", 4),
+  Config("Uint64", "int", "Uint64List", 8),
+  Config("IntPtr", "int", kDoNotEmit, kIntPtrElementSize),
+  Config("Float", "double", "Float32List", 4),
+  Config("Double", "double", "Float64List", 8),
+];
+
+//
+// Generator.
+//
+
+main(List<String> arguments) {
+  final args = argParser().parse(arguments);
+  Uri path = Uri.parse(args['path']);
+
+  generate(path, "ffi.g.dart", generatePublicExtension);
+  generate(path, "ffi_patch.g.dart", generatePatchExtension);
+}
+
+void generate(
+    Uri path, String fileName, Function(StringBuffer, Config) generator) {
+  final buffer = StringBuffer();
+  generateHeader(buffer);
+  configuration.forEach((Config c) => generator(buffer, c));
+  generateFooter(buffer);
+
+  final fullPath = path.resolve(fileName).path;
+  File(fullPath).writeAsStringSync(buffer.toString());
+  final fmtResult = Process.runSync(dartfmtPath().path, ["-w", fullPath]);
+  if (fmtResult.exitCode != 0) {
+    throw Exception(
+        "Formatting failed:\n${fmtResult.stdout}\n${fmtResult.stderr}\n");
+  }
+  print("Generated $fullPath.");
+}
+
+void generateHeader(StringBuffer buffer) {
+  const header = """
+//
+// The following code is generated, do not edit by hand.
+//
+// Code generated by `runtime/tools/ffi/sdk_lib_ffi_generator.dart`.
+//
+
+""";
+
+  buffer.write(header);
+}
+
+void generatePublicExtension(StringBuffer buffer, Config config) {
+  final nativeType = config.nativeType;
+  final dartType = config.dartType;
+  final typedListType = config.typedListType;
+  final elementSize = config.elementSize;
+
+  final bits = sizeOfBits(elementSize);
+  // final sizeInBytes =
+  // "${sizeOf(elementSize)} byte${elementSize != 1 ? "s" : ""}";
+
+  String property;
+  if (_isInt(nativeType)) {
+    if (_isSigned(nativeType)) {
+      property = "$bits-bit two's complement integer";
+    } else {
+      property = "$bits-bit unsigned integer";
+    }
+  } else if (nativeType == "Float") {
+    property = "float";
+  } else {
+    property = "double";
+  }
+
+  const platformIntPtr = """
+  ///
+  /// On 32-bit platforms this is a 32-bit integer, and on 64-bit platforms
+  /// this is a 64-bit integer.
+""";
+
+  final platform = nativeType == "IntPtr" ? platformIntPtr : "";
+
+  final intSignedTruncate = """
+  ///
+  /// A Dart integer is truncated to $bits bits (as if by `.toSigned($bits)`) before
+  /// being stored, and the $bits-bit value is sign-extended when it is loaded.
+""";
+
+  const intPtrTruncate = """
+  ///
+  /// On 32-bit platforms a Dart integer is truncated to 32 bits (as if by
+  /// `.toSigned(32)`) before being stored, and the 32-bit value is
+  /// sign-extended when it is loaded.
+""";
+
+  final intUnsignedTruncate = """
+  ///
+  /// A Dart integer is truncated to $bits bits (as if by `.toUnsigned($bits)`) before
+  /// being stored, and the $bits-bit value is zero-extended when it is loaded.
+""";
+
+  const floatTruncate = """
+  ///
+  /// A Dart double loses precision before being stored, and the float value is
+  /// converted to a double when it is loaded.
+""";
+
+  String truncate = "";
+  if (nativeType == "IntPtr") {
+    truncate = intPtrTruncate;
+  } else if (_isInt(nativeType) && elementSize != 8) {
+    truncate = _isSigned(nativeType) ? intSignedTruncate : intUnsignedTruncate;
+  } else if (nativeType == "Float") {
+    truncate = floatTruncate;
+  }
+
+  final sizeTimes =
+      elementSize != 1 ? '${bracketOr(sizeOf(elementSize))} * ' : '';
+
+  final alignmentDefault = """
+  ///
+  /// The [address] must be ${sizeOf(elementSize)}-byte aligned.
+""";
+
+  const alignmentIntptr = """
+  ///
+  /// On 32-bit platforms the [address] must be 4-byte aligned, and on 64-bit
+  /// platforms the [address] must be 8-byte aligned.
+""";
+
+  String alignment = "";
+  if (nativeType == "IntPtr") {
+    alignment = alignmentIntptr;
+  } else if (elementSize != 1) {
+    alignment = alignmentDefault;
+  }
+
+  final asTypedList = typedListType == kDoNotEmit
+      ? ""
+      : """
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + ${sizeTimes}length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+$alignment  external $typedListType asTypedList(int length);
+""";
+
+  // TODO(38892): Stop generating documentation on setter.
+  buffer.write("""
+/// Extension on [Pointer] specialized for the type argument [$nativeType].
+extension ${nativeType}Pointer on Pointer<$nativeType> {
+  /// The $property at [address].
+$platform$truncate$alignment  external $dartType get value;
+
+  /// The $property at [address].
+$platform$truncate$alignment  external void set value($dartType value);
+
+  /// The $property at `address + ${sizeTimes}index`.
+$platform$truncate$alignment  external $dartType operator [](int index);
+
+  /// The $property at `address + ${sizeTimes}index`.
+$platform$truncate$alignment  external void operator []=(int index, $dartType value);
+
+$asTypedList
+}
+
+""");
+}
+
+void generatePatchExtension(StringBuffer buffer, Config config) {
+  final nativeType = config.nativeType;
+  final dartType = config.dartType;
+  final typedListType = config.typedListType;
+
+  final asTypedList = typedListType == kDoNotEmit
+      ? ""
+      : """
+  @patch
+  $typedListType asTypedList(int elements) => _asExternalTypedData(this, elements);
+""";
+
+  buffer.write("""
+extension ${nativeType}Pointer on Pointer<$nativeType> {
+ @patch
+  $dartType get value => _load$nativeType(this, 0);
+
+  @patch
+  set value($dartType value) => _store$nativeType(this, 0, value);
+
+  @patch
+  $dartType operator [](int index) => _load$nativeType(this, index);
+
+  @patch
+  operator []=(int index, $dartType value) => _store$nativeType(this, index, value);
+
+$asTypedList
+}
+
+""");
+}
+
+void generateFooter(StringBuffer buffer) {
+  final footer = """
+//
+// End of generated code.
+//
+""";
+
+  buffer.write(footer);
+}
+
+//
+// Helper functions.
+//
+
+bool _isInt(String type) => type.startsWith("Int") || type.startsWith("Uint");
+bool _isSigned(String type) => type.startsWith("Int");
+
+String sizeOf(int size) {
+  switch (size) {
+    case kIntPtrElementSize:
+      return "4 or 8";
+    default:
+      return "$size";
+  }
+}
+
+String sizeOfBits(int size) {
+  switch (size) {
+    case kIntPtrElementSize:
+      return "32 or 64";
+    default:
+      return "${size * 8}";
+  }
+}
+
+String bracketOr(String input) {
+  if (input.contains("or")) {
+    return "($input)";
+  }
+  return input;
+}
+
+final Uri _containingFolder = File.fromUri(Platform.script).parent.uri;
+
+ArgParser argParser() {
+  final parser = ArgParser(allowTrailingOptions: false);
+  parser.addOption('path',
+      abbr: 'p',
+      help: 'Path to generate the files at.',
+      defaultsTo: _containingFolder.toString());
+  parser.addFlag('help', abbr: 'h', help: 'Display usage information.',
+      callback: (help) {
+    if (help) print(parser.usage);
+  });
+  return parser;
+}
+
+Uri dartfmtPath() {
+  // TODO(dacoharkes): Use "../../../tools/sdks/dart-sdk/bin/dartfmt" when the
+  // pinned fully supports extension methods.
+  return Uri.parse("dartfmt");
+}
+
+class Config {
+  final String nativeType;
+  final String dartType;
+  final String typedListType;
+  final int elementSize;
+  const Config(
+      this.nativeType, this.dartType, this.typedListType, this.elementSize);
+}
+
+const String kDoNotEmit = "donotemit";
+const int kIntPtrElementSize = -1;
diff --git a/runtime/vm/atomic_test.cc b/runtime/vm/atomic_test.cc
index 5f1d565..a495bb4 100644
--- a/runtime/vm/atomic_test.cc
+++ b/runtime/vm/atomic_test.cc
@@ -51,15 +51,15 @@
 }
 
 VM_UNIT_TEST_CASE(FetchOrRelaxed) {
-  uint32_t v = 42;
-  uint32_t previous = AtomicOperations::FetchOrRelaxedUint32(&v, 3);
+  RelaxedAtomic<uint32_t> v = 42;
+  uint32_t previous = v.fetch_or(3);
   EXPECT_EQ(static_cast<uint32_t>(42), previous);
   EXPECT_EQ(static_cast<uint32_t>(43), v);
 }
 
 VM_UNIT_TEST_CASE(FetchAndRelaxed) {
-  uint32_t v = 42;
-  uint32_t previous = AtomicOperations::FetchAndRelaxedUint32(&v, 3);
+  RelaxedAtomic<uint32_t> v = 42;
+  uint32_t previous = v.fetch_and(3);
   EXPECT_EQ(static_cast<uint32_t>(42), previous);
   EXPECT_EQ(static_cast<uint32_t>(2), v);
 }
diff --git a/runtime/vm/bitmap.cc b/runtime/vm/bitmap.cc
index 79bab3c..d5e25dd 100644
--- a/runtime/vm/bitmap.cc
+++ b/runtime/vm/bitmap.cc
@@ -77,6 +77,38 @@
   }
 }
 
+void BitmapBuilder::AppendAsBytesTo(GrowableArray<uint8_t>* bytes) const {
+  // Early return if there are no bits in the payload to copy.
+  if (Length() == 0) return;
+
+  const intptr_t total_size =
+      Utils::RoundUp(Length(), kBitsPerByte) / kBitsPerByte;
+  intptr_t payload_size;
+  intptr_t extra_size;
+  if (total_size > data_size_in_bytes_) {
+    // A [BitmapBuilder] does not allocate storage for the trailing 0 bits in
+    // the backing store, so we need to add additional empty bytes here.
+    payload_size = data_size_in_bytes_;
+    extra_size = total_size - data_size_in_bytes_;
+  } else {
+    payload_size = total_size;
+    extra_size = 0;
+  }
+  for (intptr_t i = 0; i < payload_size; i++) {
+    bytes->Add(data_[i]);
+  }
+  for (intptr_t i = 0; i < extra_size; i++) {
+    bytes->Add(0U);
+  }
+  // Make sure any bits in the payload beyond the bit length are cleared to
+  // ensure deterministic snapshots.
+#if defined(DEBUG)
+  if (Length() % kBitsPerByte == 0) return;
+  const int8_t mask = (1 << (Length() % kBitsPerByte)) - 1;
+  ASSERT(bytes->Last() == (bytes->Last() & mask));
+#endif
+}
+
 bool BitmapBuilder::GetBit(intptr_t bit_offset) const {
   if (!InRange(bit_offset)) {
     return false;
diff --git a/runtime/vm/bitmap.h b/runtime/vm/bitmap.h
index 469153b..878a834 100644
--- a/runtime/vm/bitmap.h
+++ b/runtime/vm/bitmap.h
@@ -6,6 +6,7 @@
 #define RUNTIME_VM_BITMAP_H_
 
 #include "vm/allocation.h"
+#include "vm/growable_array.h"
 #include "vm/thread_state.h"
 #include "vm/zone.h"
 
@@ -43,6 +44,7 @@
   void SetRange(intptr_t min, intptr_t max, bool value);
 
   void Print() const;
+  void AppendAsBytesTo(GrowableArray<uint8_t>* bytes) const;
 
  private:
   static const intptr_t kInitialSizeInBytes = 16;
diff --git a/runtime/vm/bitmap_test.cc b/runtime/vm/bitmap_test.cc
index a9a1add..8447aab 100644
--- a/runtime/vm/bitmap_test.cc
+++ b/runtime/vm/bitmap_test.cc
@@ -3,12 +3,25 @@
 // BSD-style license that can be found in the LICENSE file.
 
 #include "vm/bitmap.h"
+
 #include "platform/assert.h"
+#include "vm/code_descriptors.h"
 #include "vm/object.h"
 #include "vm/unit_test.h"
 
 namespace dart {
 
+// 0x4 is just a placeholder PC offset because no entry of a CSM should
+// have a PC offset of 0, otherwise internal assumptions break.
+static const uint32_t kTestPcOffset = 0x4;
+static const intptr_t kTestSpillSlotBitCount = 0;
+
+static RawCompressedStackMaps* MapsFromBuilder(BitmapBuilder* bmap) {
+  CompressedStackMapsBuilder builder;
+  builder.AddEntry(kTestPcOffset, bmap, kTestSpillSlotBitCount);
+  return builder.Finalize();
+}
+
 ISOLATE_UNIT_TEST_CASE(BitmapBuilder) {
   // Test basic bit map builder operations.
   BitmapBuilder* builder1 = new BitmapBuilder();
@@ -36,16 +49,23 @@
     EXPECT_EQ(value, builder1->Get(i));
     value = !value;
   }
-  // Create a StackMap object from the builder and verify its contents.
-  const StackMap& stackmap1 = StackMap::Handle(StackMap::New(builder1, 0));
-  EXPECT_EQ(1024, stackmap1.Length());
-  OS::PrintErr("%s\n", stackmap1.ToCString());
+
+  // Create a CompressedStackMaps object and verify its contents.
+  const auto& maps1 = CompressedStackMaps::Handle(MapsFromBuilder(builder1));
+  CompressedStackMapsIterator it1(maps1);
+  EXPECT(it1.MoveNext());
+
+  EXPECT_EQ(kTestPcOffset, it1.pc_offset());
+  EXPECT_EQ(kTestSpillSlotBitCount, it1.spill_slot_bit_count());
+  EXPECT_EQ(1024, it1.length());
   value = true;
   for (int32_t i = 0; i < 1024; i++) {
-    EXPECT_EQ(value, stackmap1.IsObject(i));
+    EXPECT_EQ(value, it1.IsObject(i));
     value = !value;
   }
 
+  EXPECT(!it1.MoveNext());
+
   // Test the SetRange function in the builder.
   builder1->SetRange(0, 256, false);
   EXPECT_EQ(1024, builder1->Length());
@@ -62,18 +82,26 @@
   for (int32_t i = 1025; i <= 2048; i++) {
     EXPECT(!builder1->Get(i));
   }
-  const StackMap& stackmap2 = StackMap::Handle(StackMap::New(builder1, 0));
-  EXPECT_EQ(2049, stackmap2.Length());
+
+  const auto& maps2 = CompressedStackMaps::Handle(MapsFromBuilder(builder1));
+  CompressedStackMapsIterator it2(maps2);
+  EXPECT(it2.MoveNext());
+
+  EXPECT_EQ(kTestPcOffset, it2.pc_offset());
+  EXPECT_EQ(kTestSpillSlotBitCount, it2.spill_slot_bit_count());
+  EXPECT_EQ(2049, it2.length());
   for (int32_t i = 0; i <= 256; i++) {
-    EXPECT(!stackmap2.IsObject(i));
+    EXPECT(!it2.IsObject(i));
   }
   for (int32_t i = 257; i <= 1024; i++) {
-    EXPECT(stackmap2.IsObject(i));
+    EXPECT(it2.IsObject(i));
   }
   for (int32_t i = 1025; i <= 2048; i++) {
-    EXPECT(!stackmap2.IsObject(i));
+    EXPECT(!it2.IsObject(i));
   }
 
+  EXPECT(!it2.MoveNext());
+
   // Test using SetLength to shorten the builder, followed by lengthening.
   builder1->SetLength(747);
   EXPECT_EQ(747, builder1->Length());
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 37dcfdf..7fceaf7 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -370,15 +370,33 @@
   V(VMService_RequestAssets, 0)                                                \
   V(VMService_DecodeAssets, 1)                                                 \
   V(VMService_spawnUriNotify, 2)                                               \
-  V(Ffi_allocate, 1)                                                           \
-  V(Ffi_free, 1)                                                               \
-  V(Ffi_load, 1)                                                               \
-  V(Ffi_store, 2)                                                              \
+  V(Ffi_loadInt8, 2)                                                           \
+  V(Ffi_loadInt16, 2)                                                          \
+  V(Ffi_loadInt32, 2)                                                          \
+  V(Ffi_loadInt64, 2)                                                          \
+  V(Ffi_loadUint8, 2)                                                          \
+  V(Ffi_loadUint16, 2)                                                         \
+  V(Ffi_loadUint32, 2)                                                         \
+  V(Ffi_loadUint64, 2)                                                         \
+  V(Ffi_loadIntPtr, 2)                                                         \
+  V(Ffi_loadFloat, 2)                                                          \
+  V(Ffi_loadDouble, 2)                                                         \
+  V(Ffi_loadPointer, 2)                                                        \
+  V(Ffi_loadStruct, 2)                                                         \
+  V(Ffi_storeInt8, 3)                                                          \
+  V(Ffi_storeInt16, 3)                                                         \
+  V(Ffi_storeInt32, 3)                                                         \
+  V(Ffi_storeInt64, 3)                                                         \
+  V(Ffi_storeUint8, 3)                                                         \
+  V(Ffi_storeUint16, 3)                                                        \
+  V(Ffi_storeUint32, 3)                                                        \
+  V(Ffi_storeUint64, 3)                                                        \
+  V(Ffi_storeIntPtr, 3)                                                        \
+  V(Ffi_storeFloat, 3)                                                         \
+  V(Ffi_storeDouble, 3)                                                        \
+  V(Ffi_storePointer, 3)                                                       \
   V(Ffi_address, 1)                                                            \
   V(Ffi_fromAddress, 1)                                                        \
-  V(Ffi_elementAt, 2)                                                          \
-  V(Ffi_offsetBy, 2)                                                           \
-  V(Ffi_cast, 1)                                                               \
   V(Ffi_sizeOf, 0)                                                             \
   V(Ffi_asFunctionInternal, 1)                                                 \
   V(Ffi_nativeCallbackFunction, 2)                                             \
diff --git a/runtime/vm/class_id.h b/runtime/vm/class_id.h
index 69d6487..353039d 100644
--- a/runtime/vm/class_id.h
+++ b/runtime/vm/class_id.h
@@ -31,7 +31,7 @@
   V(ObjectPool)                                                                \
   V(PcDescriptors)                                                             \
   V(CodeSourceMap)                                                             \
-  V(StackMap)                                                                  \
+  V(CompressedStackMaps)                                                       \
   V(LocalVarDescriptors)                                                       \
   V(ExceptionHandlers)                                                         \
   V(Context)                                                                   \
@@ -109,7 +109,7 @@
   V(Int32x4Array)                                                              \
   V(Float64x2Array)
 
-#define CLASS_LIST_FFI_TYPE_MARKER(V)                                          \
+#define CLASS_LIST_FFI_NUMERIC(V)                                              \
   V(Int8)                                                                      \
   V(Int16)                                                                     \
   V(Int32)                                                                     \
@@ -120,7 +120,10 @@
   V(Uint64)                                                                    \
   V(IntPtr)                                                                    \
   V(Float)                                                                     \
-  V(Double)                                                                    \
+  V(Double)
+
+#define CLASS_LIST_FFI_TYPE_MARKER(V)                                          \
+  CLASS_LIST_FFI_NUMERIC(V)                                                    \
   V(Void)
 
 #define CLASS_LIST_FFI(V)                                                      \
diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc
index a9d7943..696609f 100644
--- a/runtime/vm/class_table.cc
+++ b/runtime/vm/class_table.cc
@@ -149,9 +149,10 @@
     // Add the vtable for this predefined class into the static vtable registry
     // if it has not been setup yet.
     cpp_vtable cls_vtable = cls.handle_vtable();
-    cpp_vtable old_cls_vtable = AtomicOperations::CompareAndSwapWord(
-        &(Object::builtin_vtables_[index]), 0, cls_vtable);
-    if (old_cls_vtable != 0) {
+    cpp_vtable old_cls_vtable = 0;
+    if (!Object::builtin_vtables_[index].compare_exchange_strong(old_cls_vtable,
+                                                                 cls_vtable)) {
+      // Lost the race, but the other thread installed the same value.
       ASSERT(old_cls_vtable == cls_vtable);
     }
   } else {
diff --git a/runtime/vm/class_table.h b/runtime/vm/class_table.h
index 19b13ce..5edf9c4 100644
--- a/runtime/vm/class_table.h
+++ b/runtime/vm/class_table.h
@@ -47,12 +47,12 @@
 template <typename T>
 class AllocStats {
  public:
-  T new_count;
-  T new_size;
-  T new_external_size;
-  T old_count;
-  T old_size;
-  T old_external_size;
+  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;
@@ -62,18 +62,16 @@
   }
 
   void AddNew(T size) {
-    AtomicOperations::IncrementBy(&new_count, 1);
-    AtomicOperations::IncrementBy(&new_size, size);
+    new_count.fetch_add(1);
+    new_size.fetch_add(size);
   }
 
   void AddNewGC(T size) {
-    new_count += 1;
-    new_size += size;
+    new_count.fetch_add(1);
+    new_size.fetch_add(size);
   }
 
-  void AddNewExternal(T size) {
-    AtomicOperations::IncrementBy(&new_external_size, size);
-  }
+  void AddNewExternal(T size) { new_external_size.fetch_add(size); }
 
   void ResetOld() {
     old_count = 0;
@@ -83,18 +81,16 @@
   }
 
   void AddOld(T size, T count = 1) {
-    AtomicOperations::IncrementBy(&old_count, count);
-    AtomicOperations::IncrementBy(&old_size, size);
+    old_count.fetch_add(count);
+    old_size.fetch_add(size);
   }
 
   void AddOldGC(T size, T count = 1) {
-    old_count += count;
-    old_size += size;
+    old_count.fetch_add(count);
+    old_size.fetch_add(size);
   }
 
-  void AddOldExternal(T size) {
-    AtomicOperations::IncrementBy(&old_external_size, size);
-  }
+  void AddOldExternal(T size) { old_external_size.fetch_add(size); }
 
   void Reset() {
     ResetNew();
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index 634f9e7..45f0509 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -1180,8 +1180,7 @@
       s->Write<int32_t>(lib->ptr()->index_);
       s->Write<uint16_t>(lib->ptr()->num_imports_);
       s->Write<int8_t>(lib->ptr()->load_state_);
-      s->Write<bool>(lib->ptr()->is_dart_scheme_);
-      s->Write<bool>(lib->ptr()->debuggable_);
+      s->Write<uint8_t>(lib->ptr()->flags_);
       if (s->kind() != Snapshot::kFullAOT) {
         s->Write<uint32_t>(lib->ptr()->binary_declaration_);
       }
@@ -1218,9 +1217,8 @@
       lib->ptr()->index_ = d->Read<int32_t>();
       lib->ptr()->num_imports_ = d->Read<uint16_t>();
       lib->ptr()->load_state_ = d->Read<int8_t>();
-      lib->ptr()->is_dart_scheme_ = d->Read<bool>();
-      lib->ptr()->debuggable_ = d->Read<bool>();
-      lib->ptr()->is_in_fullsnapshot_ = true;
+      lib->ptr()->flags_ =
+          RawLibrary::InFullSnapshotBit::update(true, d->Read<uint8_t>());
 #if !defined(DART_PRECOMPILED_RUNTIME)
       if (d->kind() != Snapshot::kFullAOT) {
         lib->ptr()->binary_declaration_ = d->Read<uint32_t>();
@@ -1389,7 +1387,7 @@
 #else
     s->Push(code->ptr()->catch_entry_.variables_);
 #endif
-    s->Push(code->ptr()->stackmaps_);
+    s->Push(code->ptr()->compressed_stackmaps_);
     if (!FLAG_dwarf_stack_traces) {
       s->Push(code->ptr()->inlined_id_to_function_);
       s->Push(code->ptr()->code_source_map_);
@@ -1447,7 +1445,7 @@
 #else
       WriteField(code, catch_entry_.variables_);
 #endif
-      WriteField(code, stackmaps_);
+      WriteField(code, compressed_stackmaps_);
       if (FLAG_dwarf_stack_traces) {
         WriteFieldValue(inlined_id_to_function_, Array::null());
         WriteFieldValue(code_source_map_, CodeSourceMap::null());
@@ -1489,10 +1487,10 @@
     RawArray* code_order = nullptr;
     const intptr_t code_order_length = d->code_order_length();
     if (build_code_order) {
-      code_order = static_cast<RawArray*>(
-          AllocateUninitialized(old_space, Array::InstanceSize(count)));
+      code_order = static_cast<RawArray*>(AllocateUninitialized(
+          old_space, Array::InstanceSize(code_order_length)));
       Deserializer::InitializeHeader(code_order, kArrayCid,
-                                     Array::InstanceSize(count),
+                                     Array::InstanceSize(code_order_length),
                                      /*is_canonical=*/false);
       code_order->ptr()->type_arguments_ = TypeArguments::null();
       code_order->ptr()->length_ = Smi::New(code_order_length);
@@ -1557,7 +1555,8 @@
       code->ptr()->catch_entry_.variables_ =
           reinterpret_cast<RawSmi*>(d->ReadRef());
 #endif
-      code->ptr()->stackmaps_ = reinterpret_cast<RawArray*>(d->ReadRef());
+      code->ptr()->compressed_stackmaps_ =
+          reinterpret_cast<RawCompressedStackMaps*>(d->ReadRef());
       code->ptr()->inlined_id_to_function_ =
           reinterpret_cast<RawArray*>(d->ReadRef());
       code->ptr()->code_source_map_ =
@@ -1904,7 +1903,7 @@
 };
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
-// PcDescriptor, StackMap, OneByteString, TwoByteString
+// PcDescriptor, CompressedStackMaps, OneByteString, TwoByteString
 class RODataSerializationCluster : public SerializationCluster {
  public:
   RODataSerializationCluster(const char* name, intptr_t cid)
@@ -4449,8 +4448,9 @@
         return new (Z) RODataSerializationCluster("(RO)PcDescriptors", cid);
       case kCodeSourceMapCid:
         return new (Z) RODataSerializationCluster("(RO)CodeSourceMap", cid);
-      case kStackMapCid:
-        return new (Z) RODataSerializationCluster("(RO)StackMap", cid);
+      case kCompressedStackMapsCid:
+        return new (Z)
+            RODataSerializationCluster("(RO)CompressedStackMaps", cid);
       case kOneByteStringCid:
         return new (Z) RODataSerializationCluster("(RO)OneByteString", cid);
       case kTwoByteStringCid:
@@ -5072,7 +5072,7 @@
     switch (cid) {
       case kPcDescriptorsCid:
       case kCodeSourceMapCid:
-      case kStackMapCid:
+      case kCompressedStackMapsCid:
       case kOneByteStringCid:
       case kTwoByteStringCid:
         return new (Z) RODataDeserializationCluster();
diff --git a/runtime/vm/code_descriptors.cc b/runtime/vm/code_descriptors.cc
index fd5fd33..ee5662a 100644
--- a/runtime/vm/code_descriptors.cc
+++ b/runtime/vm/code_descriptors.cc
@@ -46,46 +46,102 @@
   return PcDescriptors::New(&encoded_data_);
 }
 
-void StackMapTableBuilder::AddEntry(intptr_t pc_offset,
-                                    BitmapBuilder* bitmap,
-                                    intptr_t register_bit_count) {
-  ASSERT(Smi::IsValid(pc_offset));
-  pc_offset_ = Smi::New(pc_offset);
-  stack_map_ = StackMap::New(bitmap, register_bit_count);
-  list_.Add(pc_offset_, Heap::kOld);
-  list_.Add(stack_map_, Heap::kOld);
+// Encode unsigned integer |value| in LEB128 format and store into |data|.
+static void EncodeLEB128(GrowableArray<uint8_t>* data, uintptr_t value) {
+  while (true) {
+    uint8_t part = value & 0x7f;
+    value >>= 7;
+    if (value != 0) part |= 0x80;
+    data->Add(part);
+    if (value == 0) break;
+  }
 }
 
-bool StackMapTableBuilder::Verify() {
-  intptr_t num_entries = Length();
-  for (intptr_t i = 1; i < num_entries; i++) {
-    pc_offset_ = OffsetAt(i - 1);
-    auto const offset1 = pc_offset_.Value();
-    pc_offset_ = OffsetAt(i);
-    auto const offset2 = pc_offset_.Value();
-    // Ensure there are no duplicates and the entries are sorted.
-    if (offset1 >= offset2) return false;
-  }
+void CompressedStackMapsBuilder::AddEntry(intptr_t pc_offset,
+                                          BitmapBuilder* bitmap,
+                                          intptr_t spill_slot_bit_count) {
+  ASSERT(bitmap != nullptr);
+  ASSERT(pc_offset > last_pc_offset_);
+  ASSERT(spill_slot_bit_count >= 0 && spill_slot_bit_count <= bitmap->Length());
+  auto const pc_delta = pc_offset - last_pc_offset_;
+  auto const non_spill_slot_bit_count = bitmap->Length() - spill_slot_bit_count;
+  EncodeLEB128(&encoded_bytes_, pc_delta);
+  EncodeLEB128(&encoded_bytes_, spill_slot_bit_count);
+  EncodeLEB128(&encoded_bytes_, non_spill_slot_bit_count);
+  bitmap->AppendAsBytesTo(&encoded_bytes_);
+  last_pc_offset_ = pc_offset;
+}
+
+RawCompressedStackMaps* CompressedStackMapsBuilder::Finalize() const {
+  if (encoded_bytes_.length() == 0) return CompressedStackMaps::null();
+  return CompressedStackMaps::New(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);
+  uword shift = 0;
+  uintptr_t value = 0;
+  uint8_t part = 0;
+  do {
+    part = data[(*byte_index)++];
+    value |= static_cast<uintptr_t>(part & 0x7f) << shift;
+    shift += 7;
+  } while ((part & 0x80) != 0);
+
+  return value;
+}
+
+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_;
+
+  // 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.
+  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;
+
   return true;
 }
 
-RawArray* StackMapTableBuilder::FinalizeStackMaps(const Code& code) {
-  ASSERT(Verify());
-  intptr_t num_entries = Length();
-  if (num_entries == 0) {
-    return Object::empty_array().raw();
-  }
-  return Array::MakeFixedLength(list_);
-}
-
-RawSmi* StackMapTableBuilder::OffsetAt(intptr_t index) const {
-  pc_offset_ ^= list_.At(2 * index);
-  return pc_offset_.raw();
-}
-
-RawStackMap* StackMapTableBuilder::MapAt(intptr_t index) const {
-  stack_map_ ^= list_.At(2 * index + 1);
-  return stack_map_.raw();
+bool CompressedStackMapsIterator::IsObject(intptr_t bit_index) const {
+  ASSERT(HasLoadedEntry());
+  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;
 }
 
 RawExceptionHandlers* ExceptionHandlerList::FinalizeExceptionHandlers(
diff --git a/runtime/vm/code_descriptors.h b/runtime/vm/code_descriptors.h
index e77a651..923de55 100644
--- a/runtime/vm/code_descriptors.h
+++ b/runtime/vm/code_descriptors.h
@@ -44,32 +44,73 @@
   DISALLOW_COPY_AND_ASSIGN(DescriptorList);
 };
 
-class StackMapTableBuilder : public ZoneAllocated {
+class CompressedStackMapsBuilder : public ZoneAllocated {
  public:
-  StackMapTableBuilder()
-      : pc_offset_(Smi::ZoneHandle()),
-        stack_map_(StackMap::ZoneHandle()),
-        list_(GrowableObjectArray::ZoneHandle(
-            GrowableObjectArray::New(Heap::kOld))) {}
-  ~StackMapTableBuilder() {}
+  CompressedStackMapsBuilder() : encoded_bytes_() {}
 
   void AddEntry(intptr_t pc_offset,
                 BitmapBuilder* bitmap,
-                intptr_t register_bit_count);
+                intptr_t spill_slot_bit_count);
 
-  bool Verify();
-
-  RawArray* FinalizeStackMaps(const Code& code);
+  RawCompressedStackMaps* Finalize() const;
 
  private:
-  intptr_t Length() const { return list_.Length() / 2; }
-  RawSmi* OffsetAt(intptr_t index) const;
-  RawStackMap* MapAt(intptr_t index) const;
+  intptr_t last_pc_offset_ = 0;
+  GrowableArray<uint8_t> encoded_bytes_;
+  DISALLOW_COPY_AND_ASSIGN(CompressedStackMapsBuilder);
+};
 
-  Smi& pc_offset_;
-  StackMap& stack_map_;
-  GrowableObjectArray& list_;
-  DISALLOW_COPY_AND_ASSIGN(StackMapTableBuilder);
+class CompressedStackMapsIterator : public ValueObject {
+ public:
+  // We use the null value to represent CompressedStackMaps with no
+  // entries, so the constructor allows them.
+  explicit CompressedStackMapsIterator(const CompressedStackMaps& maps)
+      : maps_(maps) {}
+
+  // Loads the next entry from [maps_], if any. If [maps_] is the null
+  // value, this always returns false.
+  bool MoveNext();
+
+  // Finds the entry with the given PC offset starting at the current
+  // position of the iterator. If [maps_] is the null value, this always
+  // returns false.
+  bool Find(uint32_t pc_offset) {
+    // We should never have an entry with a PC offset of 0 inside an
+    // non-empty CSM, so fail. (On DBC, a pc_offset of 0 can be provided
+    // to Find() if there's no stack map information for a given Code object.)
+    if (pc_offset == 0) return false;
+    do {
+      if (current_pc_offset_ >= pc_offset) break;
+    } while (MoveNext());
+    return current_pc_offset_ == pc_offset;
+  }
+
+  // Methods for accessing parts of an entry should not be called until
+  // a successful MoveNext() or Find() call has been made.
+
+  uint32_t pc_offset() const {
+    ASSERT(HasLoadedEntry());
+    return current_pc_offset_;
+  }
+  intptr_t length() const {
+    ASSERT(HasLoadedEntry());
+    return current_spill_slot_bit_count_ + current_non_spill_slot_bit_count_;
+  }
+  intptr_t spill_slot_bit_count() const {
+    ASSERT(HasLoadedEntry());
+    return current_spill_slot_bit_count_;
+  }
+  bool IsObject(intptr_t bit_offset) const;
+
+ private:
+  bool HasLoadedEntry() const { return next_offset_ > 0; }
+
+  const CompressedStackMaps& maps_;
+  intptr_t next_offset_ = 0;
+  uint32_t current_pc_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;
 };
 
 class ExceptionHandlerList : public ZoneAllocated {
diff --git a/runtime/vm/code_descriptors_test.cc b/runtime/vm/code_descriptors_test.cc
index 5d712ed..d959adff 100644
--- a/runtime/vm/code_descriptors_test.cc
+++ b/runtime/vm/code_descriptors_test.cc
@@ -84,10 +84,8 @@
 
   // Build and setup a stackmap for the call to 'func' in 'A.foo' in order
   // to test the traversal of stack maps when a GC happens.
-  StackMapTableBuilder* stackmap_table_builder = new StackMapTableBuilder();
-  EXPECT(stackmap_table_builder != NULL);
   BitmapBuilder* stack_bitmap = new BitmapBuilder();
-  EXPECT(stack_bitmap != NULL);
+  EXPECT(stack_bitmap != nullptr);
   stack_bitmap->Set(0, false);  // var i.
   stack_bitmap->Set(1, true);   // var s1.
   stack_bitmap->Set(2, false);  // var k.
@@ -99,16 +97,17 @@
       PcDescriptors::Handle(code.pc_descriptors());
   int call_count = 0;
   PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kUnoptStaticCall);
+  CompressedStackMapsBuilder compressed_maps_builder;
   while (iter.MoveNext()) {
-    stackmap_table_builder->AddEntry(iter.PcOffset(), stack_bitmap, 0);
+    compressed_maps_builder.AddEntry(iter.PcOffset(), stack_bitmap, 0);
     ++call_count;
   }
   // We can't easily check that we put the stackmap at the correct pc, but
   // we did if there was exactly one call seen.
   EXPECT(call_count == 1);
-  const Array& stack_maps =
-      Array::Handle(stackmap_table_builder->FinalizeStackMaps(code));
-  code.set_stackmaps(stack_maps);
+  const auto& compressed_maps =
+      CompressedStackMaps::Handle(compressed_maps_builder.Finalize());
+  code.set_compressed_stackmaps(compressed_maps);
 
   // Now invoke 'A.moo' and it will trigger a GC when the native function
   // is called, this should then cause the stack map of function 'A.foo'
diff --git a/runtime/vm/compiler/aot/aot_call_specializer.cc b/runtime/vm/compiler/aot/aot_call_specializer.cc
index 1697657..12f61e2 100644
--- a/runtime/vm/compiler/aot/aot_call_specializer.cc
+++ b/runtime/vm/compiler/aot/aot_call_specializer.cc
@@ -197,13 +197,14 @@
 
     ZoneGrowableArray<PushArgumentInstr*>* args =
         new (Z) ZoneGrowableArray<PushArgumentInstr*>(2);
-    PushArgumentInstr* arg =
+    PushArgumentInstr* arg1 =
         new (Z) PushArgumentInstr(new (Z) Value(left->ArgumentAt(0)));
-    InsertBefore(call, arg, NULL, FlowGraph::kEffect);
-    args->Add(arg);
-    arg = new (Z) PushArgumentInstr(new (Z) Value(right->ArgumentAt(0)));
-    InsertBefore(call, arg, NULL, FlowGraph::kEffect);
-    args->Add(arg);
+    InsertBefore(call, arg1, nullptr, FlowGraph::kEffect);
+    args->Add(arg1);
+    PushArgumentInstr* arg2 =
+        new (Z) PushArgumentInstr(new (Z) Value(right->ArgumentAt(0)));
+    InsertBefore(call, arg2, nullptr, FlowGraph::kEffect);
+    args->Add(arg2);
     const intptr_t kTypeArgsLen = 0;
     StaticCallInstr* static_call = new (Z) StaticCallInstr(
         call->token_pos(), have_same_runtime_type, kTypeArgsLen,
@@ -211,6 +212,7 @@
         args, call->deopt_id(), call->CallCount(), ICData::kOptimized);
     static_call->SetResultType(Z, CompileType::FromCid(kBoolCid));
     ReplaceCall(call, static_call);
+    static_call->RepairPushArgsInEnvironment();
     return true;
   }
 
@@ -1119,17 +1121,21 @@
 
   // Insert all new instructions, except .call() invocation into the
   // graph.
-  for (intptr_t i = 0; i < invoke_get->ArgumentCount(); i++) {
-    InsertBefore(call, invoke_get->PushArgumentAt(i), NULL, FlowGraph::kEffect);
+  Environment* get_env =
+      call->env()->DeepCopy(Z, call->env()->Length() - call->ArgumentCount());
+  for (intptr_t i = 0, n = invoke_get->ArgumentCount(); i < n; i++) {
+    PushArgumentInstr* push = invoke_get->PushArgumentAt(i);
+    InsertBefore(call, push, nullptr, FlowGraph::kEffect);
+    get_env->PushValue(new (Z) Value(push));  // add PushArg to getter's env
   }
-  InsertBefore(call, invoke_get, call->env(), FlowGraph::kValue);
-  for (intptr_t i = 0; i < invoke_call->ArgumentCount(); i++) {
-    InsertBefore(call, invoke_call->PushArgumentAt(i), NULL,
+  InsertBefore(call, invoke_get, get_env, FlowGraph::kValue);
+  for (intptr_t i = 0, n = invoke_call->ArgumentCount(); i < n; i++) {
+    InsertBefore(call, invoke_call->PushArgumentAt(i), nullptr,
                  FlowGraph::kEffect);
   }
   // Replace original PushArguments in the graph (mainly env uses).
   ASSERT(call->ArgumentCount() == invoke_call->ArgumentCount());
-  for (intptr_t i = 0; i < call->ArgumentCount(); i++) {
+  for (intptr_t i = 0, n = call->ArgumentCount(); i < n; i++) {
     call->PushArgumentAt(i)->ReplaceUsesWith(invoke_call->PushArgumentAt(i));
     call->PushArgumentAt(i)->RemoveFromGraph();
   }
@@ -1237,7 +1243,7 @@
   Environment* copy =
       call->env()->DeepCopy(Z, call->env()->Length() - call->ArgumentCount());
   for (intptr_t i = 0; i < args->length(); ++i) {
-    copy->PushValue(new (Z) Value((*args)[i]->value()->definition()));
+    copy->PushValue(new (Z) Value((*args)[i]));  // add PushArg to env
   }
   call->RemoveEnvironment();
   ReplaceCall(call, new_call);
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc
index 1de73f8..4f32164 100644
--- a/runtime/vm/compiler/aot/precompiler.cc
+++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -2750,22 +2750,56 @@
 
 RawString* Obfuscator::ObfuscationState::BuildRename(const String& name,
                                                      bool atomic) {
-  const bool is_private = name.CharAt(0) == '_';
-  if (!atomic && is_private) {
+  if (atomic) {
+    return NewAtomicRename(name.CharAt(0) == '_');
+  }
+
+  intptr_t start = 0;
+  intptr_t end = name.Length();
+
+  // Follow the rules:
+  //
+  //         Rename(get:foo) = get:Rename(foo).
+  //         Rename(set:foo) = set:Rename(foo).
+  //
+  bool is_getter = false;
+  bool is_setter = false;
+  if (Field::IsGetterName(name)) {
+    is_getter = true;
+    start = kGetterPrefixLength;
+  } else if (Field::IsSetterName(name)) {
+    is_setter = true;
+    start = kSetterPrefixLength;
+  }
+
+  // Follow the rule:
+  //
+  //         Rename(_ident@key) = Rename(_ident)@private_key_.
+  //
+  const bool is_private = name.CharAt(start) == '_';
+  if (is_private) {
     // Find the first '@'.
-    intptr_t i = 0;
+    intptr_t i = start;
     while (i < name.Length() && name.CharAt(i) != '@') {
       i++;
     }
-    const intptr_t end = i;
+    end = i;
+  }
 
-    // Follow the rule:
-    //
-    //         Rename(_ident@key) = Rename(_ident)@private_key_.
-    //
-    string_ = Symbols::New(thread_, name, 0, end);
+  if (is_getter || is_setter || is_private) {
+    string_ = Symbols::New(thread_, name, start, end - start);
+    // It's OK to call RenameImpl() recursively because 'string_' is used
+    // only if atomic == false.
     string_ = RenameImpl(string_, /*atomic=*/true);
-    return Symbols::FromConcat(thread_, string_, private_key_);
+    if (is_private && (end < name.Length())) {
+      string_ = Symbols::FromConcat(thread_, string_, private_key_);
+    }
+    if (is_getter) {
+      return Symbols::FromGet(thread_, string_);
+    } else if (is_setter) {
+      return Symbols::FromSet(thread_, string_);
+    }
+    return string_.raw();
   } else {
     return NewAtomicRename(is_private);
   }
diff --git a/runtime/vm/compiler/aot/precompiler.h b/runtime/vm/compiler/aot/precompiler.h
index 545f193..47e4d9e 100644
--- a/runtime/vm/compiler/aot/precompiler.h
+++ b/runtime/vm/compiler/aot/precompiler.h
@@ -477,9 +477,10 @@
     // Note: |name| *must* be a Symbol.
     //
     // By default renames are aware about mangling scheme used for private
-    // names: '_ident@key' and '_ident' will be renamed consistently. If such
-    // interpretation is undesirable e.g. it is known that name does not
-    // contain a private key suffix or name is not a Dart identifier at all
+    // names, getters and setters: '_ident@key', 'get:_ident@key' and
+    // '_ident' will be renamed consistently. If such interpretation is
+    // undesirable e.g. it is known that name does not contain a private
+    // key suffix or name is not a Dart identifier at all
     // then this function should be called with |atomic| set to true.
     //
     // Note: if obfuscator was created with private_key then all
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.cc b/runtime/vm/compiler/assembler/assembler_arm64.cc
index ad41da5..fff9a9d 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64.cc
@@ -1770,6 +1770,22 @@
                                              intptr_t index_scale,
                                              Register array,
                                              Register index) {
+  return ElementAddressForRegIndexWithSize(is_load,
+                                           is_external,
+                                           cid,
+                                           Address::OperandSizeFor(cid),
+                                           index_scale,
+                                           array,
+                                           index);
+}
+
+Address Assembler::ElementAddressForRegIndexWithSize(bool is_load,
+                                                     bool is_external,
+                                                     intptr_t cid,
+                                                     OperandSize size,
+                                                     intptr_t index_scale,
+                                                     Register array,
+                                                     Register index) {
   // Note that index is expected smi-tagged, (i.e, LSL 1) for all arrays.
   const intptr_t shift = Utils::ShiftForPowerOfTwo(index_scale) - kSmiTagShift;
   const int32_t offset =
@@ -1785,7 +1801,6 @@
   } else {
     add(base, array, Operand(index, LSL, shift));
   }
-  const OperandSize size = Address::OperandSizeFor(cid);
   ASSERT(Address::CanHoldOffset(offset, Address::Offset, size));
   return Address(base, offset, Address::Offset, size);
 }
@@ -1814,79 +1829,6 @@
   }
 }
 
-void Assembler::LoadUnaligned(Register dst,
-                              Register addr,
-                              Register tmp,
-                              OperandSize sz) {
-  ASSERT(dst != addr);
-  ldr(dst, Address(addr, 0), kUnsignedByte);
-  if (sz == kHalfword) {
-    ldr(tmp, Address(addr, 1), kByte);
-    orr(dst, dst, Operand(tmp, LSL, 8));
-    return;
-  }
-  ldr(tmp, Address(addr, 1), kUnsignedByte);
-  orr(dst, dst, Operand(tmp, LSL, 8));
-  if (sz == kUnsignedHalfword) {
-    return;
-  }
-  ldr(tmp, Address(addr, 2), kUnsignedByte);
-  orr(dst, dst, Operand(tmp, LSL, 16));
-  if (sz == kWord) {
-    ldr(tmp, Address(addr, 3), kByte);
-    orr(dst, dst, Operand(tmp, LSL, 24));
-    return;
-  }
-  ldr(tmp, Address(addr, 3), kUnsignedByte);
-  orr(dst, dst, Operand(tmp, LSL, 24));
-  if (sz == kUnsignedWord) {
-    return;
-  }
-  ldr(tmp, Address(addr, 4), kUnsignedByte);
-  orr(dst, dst, Operand(tmp, LSL, 32));
-  ldr(tmp, Address(addr, 5), kUnsignedByte);
-  orr(dst, dst, Operand(tmp, LSL, 40));
-  ldr(tmp, Address(addr, 6), kUnsignedByte);
-  orr(dst, dst, Operand(tmp, LSL, 48));
-  ldr(tmp, Address(addr, 7), kUnsignedByte);
-  orr(dst, dst, Operand(tmp, LSL, 56));
-  if (sz == kDoubleWord) {
-    return;
-  }
-  UNIMPLEMENTED();
-}
-
-void Assembler::StoreUnaligned(Register src,
-                               Register addr,
-                               Register tmp,
-                               OperandSize sz) {
-  str(src, Address(addr, 0), kUnsignedByte);
-  LsrImmediate(tmp, src, 8);
-  str(tmp, Address(addr, 1), kUnsignedByte);
-  if ((sz == kHalfword) || (sz == kUnsignedHalfword)) {
-    return;
-  }
-  LsrImmediate(tmp, src, 16);
-  str(tmp, Address(addr, 2), kUnsignedByte);
-  LsrImmediate(tmp, src, 24);
-  str(tmp, Address(addr, 3), kUnsignedByte);
-  if ((sz == kWord) || (sz == kUnsignedWord)) {
-    return;
-  }
-  LsrImmediate(tmp, src, 32);
-  str(tmp, Address(addr, 4), kUnsignedByte);
-  LsrImmediate(tmp, src, 40);
-  str(tmp, Address(addr, 5), kUnsignedByte);
-  LsrImmediate(tmp, src, 48);
-  str(tmp, Address(addr, 6), kUnsignedByte);
-  LsrImmediate(tmp, src, 56);
-  str(tmp, Address(addr, 7), kUnsignedByte);
-  if (sz == kDoubleWord) {
-    return;
-  }
-  UNIMPLEMENTED();
-}
-
 void Assembler::PushRegisters(const RegisterSet& regs) {
   const intptr_t fpu_regs_count = regs.FpuRegisterCount();
   if (fpu_regs_count > 0) {
diff --git a/runtime/vm/compiler/assembler/assembler_arm64.h b/runtime/vm/compiler/assembler/assembler_arm64.h
index 6053347..1df9333 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64.h
+++ b/runtime/vm/compiler/assembler/assembler_arm64.h
@@ -1641,6 +1641,18 @@
                                     intptr_t index_scale,
                                     Register array,
                                     Register index);
+
+  // Special version of ElementAddressForRegIndex for the case when cid and
+  // operand size for the target load don't match (e.g. when loading a few
+  // elements of the array with one load).
+  Address ElementAddressForRegIndexWithSize(bool is_load,
+                                            bool is_external,
+                                            intptr_t cid,
+                                            OperandSize size,
+                                            intptr_t index_scale,
+                                            Register array,
+                                            Register index);
+
   void LoadElementAddressForRegIndex(Register address,
                                      bool is_load,
                                      bool is_external,
@@ -1649,12 +1661,6 @@
                                      Register array,
                                      Register index);
 
-  void LoadUnaligned(Register dst, Register addr, Register tmp, OperandSize sz);
-  void StoreUnaligned(Register src,
-                      Register addr,
-                      Register tmp,
-                      OperandSize sz);
-
   static int32_t EncodeImm26BranchOffset(int64_t imm, int32_t instr) {
     const int32_t imm32 = static_cast<int32_t>(imm);
     const int32_t off = (((imm32 >> 2) << kImm26Shift) & kImm26Mask);
diff --git a/runtime/vm/compiler/assembler/assembler_arm64_test.cc b/runtime/vm/compiler/assembler/assembler_arm64_test.cc
index fc38188..c993976 100644
--- a/runtime/vm/compiler/assembler/assembler_arm64_test.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm64_test.cc
@@ -1925,7 +1925,7 @@
 }
 
 ASSEMBLER_TEST_GENERATE(LoadHalfWordUnaligned, assembler) {
-  __ LoadUnaligned(R1, R0, TMP, kHalfword);
+  __ ldr(R1, R0, kHalfword);
   __ mov(R0, R1);
   __ ret();
 }
@@ -1948,7 +1948,7 @@
 }
 
 ASSEMBLER_TEST_GENERATE(LoadHalfWordUnsignedUnaligned, assembler) {
-  __ LoadUnaligned(R1, R0, TMP, kUnsignedHalfword);
+  __ ldr(R1, R0, kUnsignedHalfword);
   __ mov(R0, R1);
   __ ret();
 }
@@ -1970,7 +1970,7 @@
 
 ASSEMBLER_TEST_GENERATE(StoreHalfWordUnaligned, assembler) {
   __ LoadImmediate(R1, 0xABCD);
-  __ StoreUnaligned(R1, R0, TMP, kHalfword);
+  __ str(R1, R0, kHalfword);
   __ mov(R0, R1);
   __ ret();
 }
@@ -1998,7 +1998,7 @@
 }
 
 ASSEMBLER_TEST_GENERATE(LoadWordUnaligned, assembler) {
-  __ LoadUnaligned(R1, R0, TMP, kUnsignedWord);
+  __ ldr(R1, R0, kUnsignedWord);
   __ mov(R0, R1);
   __ ret();
 }
@@ -2028,7 +2028,7 @@
 
 ASSEMBLER_TEST_GENERATE(StoreWordUnaligned, assembler) {
   __ LoadImmediate(R1, 0x12345678);
-  __ StoreUnaligned(R1, R0, TMP, kUnsignedWord);
+  __ str(R1, R0, kUnsignedWord);
   __ mov(R0, R1);
   __ ret();
 }
diff --git a/runtime/vm/compiler/assembler/assembler_arm_test.cc b/runtime/vm/compiler/assembler/assembler_arm_test.cc
index ca70de7..c2c9030 100644
--- a/runtime/vm/compiler/assembler/assembler_arm_test.cc
+++ b/runtime/vm/compiler/assembler/assembler_arm_test.cc
@@ -14,6 +14,54 @@
 namespace dart {
 namespace compiler {
 
+TEST_CASE(ReciprocalOps) {
+  EXPECT_EQ(true, isinf(ReciprocalEstimate(-0.0f)));
+  EXPECT_EQ(true, signbit(ReciprocalEstimate(-0.0f)));
+  EXPECT_EQ(true, isinf(ReciprocalEstimate(0.0f)));
+  EXPECT_EQ(true, !signbit(ReciprocalEstimate(0.0f)));
+  EXPECT_EQ(true, isnan(ReciprocalEstimate(NAN)));
+
+#define AS_UINT32(v) (bit_cast<uint32_t, float>(v))
+#define EXPECT_BITWISE_EQ(a, b) EXPECT_EQ(AS_UINT32(a), AS_UINT32(b))
+
+  EXPECT_BITWISE_EQ(0.0f, ReciprocalEstimate(kPosInfinity));
+  EXPECT_BITWISE_EQ(-0.0f, ReciprocalEstimate(kNegInfinity));
+  EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(0.0f, kPosInfinity));
+  EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(0.0f, kNegInfinity));
+  EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(-0.0f, kPosInfinity));
+  EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(-0.0f, kNegInfinity));
+  EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(kPosInfinity, 0.0f));
+  EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(kNegInfinity, 0.0f));
+  EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(kPosInfinity, -0.0f));
+  EXPECT_BITWISE_EQ(2.0f, ReciprocalStep(kNegInfinity, -0.0f));
+  EXPECT_EQ(true, isnan(ReciprocalStep(NAN, 1.0f)));
+  EXPECT_EQ(true, isnan(ReciprocalStep(1.0f, NAN)));
+
+  EXPECT_EQ(true, isnan(ReciprocalSqrtEstimate(-1.0f)));
+  EXPECT_EQ(true, isnan(ReciprocalSqrtEstimate(kNegInfinity)));
+  EXPECT_EQ(true, isnan(ReciprocalSqrtEstimate(-1.0f)));
+  EXPECT_EQ(true, isinf(ReciprocalSqrtEstimate(-0.0f)));
+  EXPECT_EQ(true, signbit(ReciprocalSqrtEstimate(-0.0f)));
+  EXPECT_EQ(true, isinf(ReciprocalSqrtEstimate(0.0f)));
+  EXPECT_EQ(true, !signbit(ReciprocalSqrtEstimate(0.0f)));
+  EXPECT_EQ(true, isnan(ReciprocalSqrtEstimate(NAN)));
+  EXPECT_BITWISE_EQ(0.0f, ReciprocalSqrtEstimate(kPosInfinity));
+
+  EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(0.0f, kPosInfinity));
+  EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(0.0f, kNegInfinity));
+  EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(-0.0f, kPosInfinity));
+  EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(-0.0f, kNegInfinity));
+  EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(kPosInfinity, 0.0f));
+  EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(kNegInfinity, 0.0f));
+  EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(kPosInfinity, -0.0f));
+  EXPECT_BITWISE_EQ(1.5f, ReciprocalSqrtStep(kNegInfinity, -0.0f));
+  EXPECT_EQ(true, isnan(ReciprocalSqrtStep(NAN, 1.0f)));
+  EXPECT_EQ(true, isnan(ReciprocalSqrtStep(1.0f, NAN)));
+
+#undef AS_UINT32
+#undef EXPECT_BITWISE_EQ
+}
+
 #define __ assembler->
 
 ASSEMBLER_TEST_GENERATE(Simple, assembler) {
@@ -3430,43 +3478,6 @@
   }
 }
 
-// This is the same function as in the Simulator.
-static float arm_recip_estimate(float a) {
-  // From the ARM Architecture Reference Manual A2-85.
-  if (isinf(a) || (fabs(a) >= exp2f(126)))
-    return 0.0;
-  else if (a == 0.0)
-    return kPosInfinity;
-  else if (isnan(a))
-    return a;
-
-  uint32_t a_bits = bit_cast<uint32_t, float>(a);
-  // scaled = '0011 1111 1110' : a<22:0> : Zeros(29)
-  uint64_t scaled = (static_cast<uint64_t>(0x3fe) << 52) |
-                    ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
-  // result_exp = 253 - UInt(a<30:23>)
-  int32_t result_exp = 253 - ((a_bits >> 23) & 0xff);
-  ASSERT((result_exp >= 1) && (result_exp <= 252));
-
-  double scaled_d = bit_cast<double, uint64_t>(scaled);
-  ASSERT((scaled_d >= 0.5) && (scaled_d < 1.0));
-
-  // a in units of 1/512 rounded down.
-  int32_t q = static_cast<int32_t>(scaled_d * 512.0);
-  // reciprocal r.
-  double r = 1.0 / ((static_cast<double>(q) + 0.5) / 512.0);
-  // r in units of 1/256 rounded to nearest.
-  int32_t s = static_cast<int32_t>(256.0 * r + 0.5);
-  double estimate = static_cast<double>(s) / 256.0;
-  ASSERT((estimate >= 1.0) && (estimate <= (511.0 / 256.0)));
-
-  // result = sign : result_exp<7:0> : estimate<51:29>
-  int32_t result_bits =
-      (a_bits & 0x80000000) | ((result_exp & 0xff) << 23) |
-      ((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff);
-  return bit_cast<float, int32_t>(result_bits);
-}
-
 ASSEMBLER_TEST_GENERATE(Vrecpeqs, assembler) {
   if (TargetCPUFeatures::neon_supported()) {
     __ LoadSImmediate(S4, 147.0);
@@ -3483,7 +3494,7 @@
   if (TargetCPUFeatures::neon_supported()) {
     typedef float (*Vrecpeqs)() DART_UNUSED;
     float res = EXECUTE_TEST_CODE_FLOAT(Vrecpeqs, test->entry());
-    EXPECT_FLOAT_EQ(arm_recip_estimate(147.0), res, 0.0001f);
+    EXPECT_FLOAT_EQ(ReciprocalEstimate(147.0), res, 0.0001f);
   }
 }
 
@@ -3540,60 +3551,6 @@
   }
 }
 
-static float arm_reciprocal_sqrt_estimate(float a) {
-  // From the ARM Architecture Reference Manual A2-87.
-  if (isinf(a) || (fabs(a) >= exp2f(126)))
-    return 0.0;
-  else if (a == 0.0)
-    return kPosInfinity;
-  else if (isnan(a))
-    return a;
-
-  uint32_t a_bits = bit_cast<uint32_t, float>(a);
-  uint64_t scaled;
-  if (((a_bits >> 23) & 1) != 0) {
-    // scaled = '0 01111111101' : operand<22:0> : Zeros(29)
-    scaled = (static_cast<uint64_t>(0x3fd) << 52) |
-             ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
-  } else {
-    // scaled = '0 01111111110' : operand<22:0> : Zeros(29)
-    scaled = (static_cast<uint64_t>(0x3fe) << 52) |
-             ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
-  }
-  // result_exp = (380 - UInt(operand<30:23>) DIV 2;
-  int32_t result_exp = (380 - ((a_bits >> 23) & 0xff)) / 2;
-
-  double scaled_d = bit_cast<double, uint64_t>(scaled);
-  ASSERT((scaled_d >= 0.25) && (scaled_d < 1.0));
-
-  double r;
-  if (scaled_d < 0.5) {
-    // range 0.25 <= a < 0.5
-
-    // a in units of 1/512 rounded down.
-    int32_t q0 = static_cast<int32_t>(scaled_d * 512.0);
-    // reciprocal root r.
-    r = 1.0 / sqrt((static_cast<double>(q0) + 0.5) / 512.0);
-  } else {
-    // range 0.5 <= a < 1.0
-
-    // a in units of 1/256 rounded down.
-    int32_t q1 = static_cast<int32_t>(scaled_d * 256.0);
-    // reciprocal root r.
-    r = 1.0 / sqrt((static_cast<double>(q1) + 0.5) / 256.0);
-  }
-  // r in units of 1/256 rounded to nearest.
-  int32_t s = static_cast<int>(256.0 * r + 0.5);
-  double estimate = static_cast<double>(s) / 256.0;
-  ASSERT((estimate >= 1.0) && (estimate <= (511.0 / 256.0)));
-
-  // result = 0 : result_exp<7:0> : estimate<51:29>
-  int32_t result_bits =
-      ((result_exp & 0xff) << 23) |
-      ((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff);
-  return bit_cast<float, int32_t>(result_bits);
-}
-
 ASSEMBLER_TEST_GENERATE(Vrsqrteqs, assembler) {
   if (TargetCPUFeatures::neon_supported()) {
     __ LoadSImmediate(S4, 147.0);
@@ -3611,7 +3568,7 @@
   if (TargetCPUFeatures::neon_supported()) {
     typedef float (*Vrsqrteqs)() DART_UNUSED;
     float res = EXECUTE_TEST_CODE_FLOAT(Vrsqrteqs, test->entry());
-    EXPECT_FLOAT_EQ(arm_reciprocal_sqrt_estimate(147.0), res, 0.0001f);
+    EXPECT_FLOAT_EQ(ReciprocalSqrtEstimate(147.0), res, 0.0001f);
   }
 }
 
diff --git a/runtime/vm/compiler/assembler/disassembler.cc b/runtime/vm/compiler/assembler/disassembler.cc
index 64cd1af..b74310c 100644
--- a/runtime/vm/compiler/assembler/disassembler.cc
+++ b/runtime/vm/compiler/assembler/disassembler.cc
@@ -279,15 +279,10 @@
 #endif  // !defined(DART_PRECOMPILED_RUNTIME)
 
   THR_Print("StackMaps for function '%s' {\n", function_fullname);
-  if (code.stackmaps() != Array::null()) {
-    const Array& stackmap_table = Array::Handle(zone, code.stackmaps());
-    auto& offset = Smi::Handle(zone);
-    StackMap& map = StackMap::Handle(zone);
-    for (intptr_t i = 0; i < stackmap_table.Length(); i += 2) {
-      offset ^= stackmap_table.At(i);
-      map ^= stackmap_table.At(i + 1);
-      THR_Print("0x%08" Px ": %s\n", offset.Value(), map.ToCString());
-    }
+  if (code.compressed_stackmaps() != CompressedStackMaps::null()) {
+    const auto& stackmaps =
+        CompressedStackMaps::Handle(zone, code.compressed_stackmaps());
+    THR_Print("%s\n", stackmaps.ToCString());
   }
   THR_Print("}\n");
 
diff --git a/runtime/vm/compiler/backend/bce_test.cc b/runtime/vm/compiler/backend/bce_test.cc
index d7f508c..2bef2ba 100644
--- a/runtime/vm/compiler/backend/bce_test.cc
+++ b/runtime/vm/compiler/backend/bce_test.cc
@@ -67,8 +67,8 @@
                           intptr_t expected_before,
                           intptr_t expected_after) {
   auto jit_result = ApplyBCE(script_chars, CompilerPass::kJIT);
-  EXPECT_STREQ(expected_before, jit_result.first);
-  EXPECT_STREQ(expected_after, jit_result.second);
+  EXPECT_EQ(expected_before, jit_result.first);
+  EXPECT_EQ(expected_after, jit_result.second);
 }
 
 //
diff --git a/runtime/vm/compiler/backend/flow_graph.cc b/runtime/vm/compiler/backend/flow_graph.cc
index 39e8dc5..3cc78fa 100644
--- a/runtime/vm/compiler/backend/flow_graph.cc
+++ b/runtime/vm/compiler/backend/flow_graph.cc
@@ -400,6 +400,9 @@
     Class& cls = Class::Handle(zone());
     Function& fun = Function::Handle(zone());
     for (intptr_t i = 0, len = data->NumberOfChecks(); i < len; i++) {
+      if (!data->IsUsedAt(i)) {
+        continue;  // do not consider
+      }
       fun = data->GetTargetAt(i);
       cls = fun.Owner();
       if (data->GetReceiverClassIdAt(i) == cid || cls.id() == cid) {
diff --git a/runtime/vm/compiler/backend/flow_graph_checker.cc b/runtime/vm/compiler/backend/flow_graph_checker.cc
index 0bbb995..d0b3108 100644
--- a/runtime/vm/compiler/backend/flow_graph_checker.cc
+++ b/runtime/vm/compiler/backend/flow_graph_checker.cc
@@ -106,6 +106,28 @@
          instruction->IsStop() || instruction->IsTailCall();
 }
 
+// Asserts push arguments appear in environment at the right place.
+static void AssertPushArgsInEnv(FlowGraph* flow_graph, Definition* call) {
+  Environment* env = call->env();
+  if (env == nullptr) {
+    // An empty environment should only happen pre-SSA.
+    ASSERT(flow_graph->current_ssa_temp_index() == 0);
+  } else if (flow_graph->function().IsIrregexpFunction()) {
+    // TODO(dartbug.com/38577): cleanup regexp pipeline too....
+  } else {
+    // Otherwise, the trailing environment entries must
+    // correspond directly with the PushArguments.
+    const intptr_t env_count = env->Length();
+    const intptr_t arg_count = call->ArgumentCount();
+    ASSERT(arg_count <= env_count);
+    const intptr_t env_base = env_count - arg_count;
+    for (intptr_t i = 0; i < arg_count; i++) {
+      ASSERT(call->PushArgumentAt(i) ==
+             env->ValueAt(env_base + i)->definition());
+    }
+  }
+}
+
 void FlowGraphChecker::VisitBlocks() {
   const GrowableArray<BlockEntryInstr*>& preorder = flow_graph_->preorder();
   const GrowableArray<BlockEntryInstr*>& postorder = flow_graph_->postorder();
@@ -225,9 +247,9 @@
 void FlowGraphChecker::VisitInstruction(Instruction* instruction) {
   ASSERT(!instruction->IsBlockEntry());
 
+#if !defined(DART_PRECOMPILER)
   // In JIT mode, any instruction which may throw must have a deopt-id, except
   // tail-call because it replaces the stack frame.
-#if !defined(DART_PRECOMPILER)
   ASSERT(!instruction->MayThrow() || instruction->IsTailCall() ||
          instruction->deopt_id() != DeoptId::kNone);
 #endif  // !defined(DART_PRECOMPILER)
@@ -394,7 +416,16 @@
   ASSERT(def->value()->definition() != def);
 }
 
+void FlowGraphChecker::VisitClosureCall(ClosureCallInstr* call) {
+  AssertPushArgsInEnv(flow_graph_, call);
+}
+
+void FlowGraphChecker::VisitStaticCall(StaticCallInstr* call) {
+  AssertPushArgsInEnv(flow_graph_, call);
+}
+
 void FlowGraphChecker::VisitInstanceCall(InstanceCallInstr* call) {
+  AssertPushArgsInEnv(flow_graph_, call);
   // Force-optimized functions may not have instance calls inside them because
   // we do not reset ICData for these.
   ASSERT(!flow_graph_->function().ForceOptimize());
@@ -402,6 +433,7 @@
 
 void FlowGraphChecker::VisitPolymorphicInstanceCall(
     PolymorphicInstanceCallInstr* call) {
+  AssertPushArgsInEnv(flow_graph_, call);
   // Force-optimized functions may not have instance calls inside them because
   // we do not reset ICData for these.
   ASSERT(!flow_graph_->function().ForceOptimize());
diff --git a/runtime/vm/compiler/backend/flow_graph_checker.h b/runtime/vm/compiler/backend/flow_graph_checker.h
index 63a77bd..c86fab8 100644
--- a/runtime/vm/compiler/backend/flow_graph_checker.h
+++ b/runtime/vm/compiler/backend/flow_graph_checker.h
@@ -56,9 +56,11 @@
   void VisitIndirectGoto(IndirectGotoInstr* jmp) override;
   void VisitBranch(BranchInstr* branch) override;
   void VisitRedefinition(RedefinitionInstr* def) override;
-  void VisitInstanceCall(InstanceCallInstr* instr) override;
+  void VisitClosureCall(ClosureCallInstr* call) override;
+  void VisitStaticCall(StaticCallInstr* call) override;
+  void VisitInstanceCall(InstanceCallInstr* call) override;
   void VisitPolymorphicInstanceCall(
-      PolymorphicInstanceCallInstr* instr) override;
+      PolymorphicInstanceCallInstr* call) override;
 
   FlowGraph* const flow_graph_;
   BlockEntryInstr* current_block_;
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index 27600c2..ecc7b50 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -119,12 +119,12 @@
       parsed_function_(parsed_function),
       flow_graph_(*flow_graph),
       block_order_(*flow_graph->CodegenBlockOrder(is_optimizing)),
-      current_block_(NULL),
-      exception_handlers_list_(NULL),
-      pc_descriptors_list_(NULL),
-      stackmap_table_builder_(NULL),
-      code_source_map_builder_(NULL),
-      catch_entry_moves_maps_builder_(NULL),
+      current_block_(nullptr),
+      exception_handlers_list_(nullptr),
+      pc_descriptors_list_(nullptr),
+      compressed_stackmaps_builder_(nullptr),
+      code_source_map_builder_(nullptr),
+      catch_entry_moves_maps_builder_(nullptr),
       block_info_(block_order_.length()),
       deopt_infos_(),
       static_calls_target_table_(),
@@ -932,11 +932,8 @@
       bitmap->Set(bitmap->Length(), true);
     }
 
-    // The slow path area Outside the spill area contains are live registers
-    // and pushed arguments for calls inside the slow path.
-    intptr_t slow_path_bit_count = bitmap->Length() - spill_area_size;
-    stackmap_table_builder()->AddEntry(assembler()->CodeSize(), bitmap,
-                                       slow_path_bit_count);
+    compressed_stackmaps_builder()->AddEntry(assembler()->CodeSize(), bitmap,
+                                             spill_area_size);
   }
 }
 
@@ -947,30 +944,29 @@
 //     MaterializeObjectInstr::RemapRegisters
 //
 Environment* FlowGraphCompiler::SlowPathEnvironmentFor(
-    Instruction* instruction,
+    Environment* env,
+    LocationSummary* locs,
     intptr_t num_slow_path_args) {
-  const bool using_shared_stub =
-      instruction->locs()->call_on_shared_slow_path();
+  const bool using_shared_stub = locs->call_on_shared_slow_path();
   const bool shared_stub_save_fpu_registers =
-      using_shared_stub &&
-      instruction->locs()->live_registers()->FpuRegisterCount() > 0;
+      using_shared_stub && locs->live_registers()->FpuRegisterCount() > 0;
   // TODO(sjindel): Modify logic below to account for slow-path args with shared
   // stubs.
   ASSERT(!using_shared_stub || num_slow_path_args == 0);
-  if (instruction->env() == NULL) {
+  if (env == nullptr) {
     ASSERT(!is_optimizing());
-    return NULL;
+    return nullptr;
   }
 
-  Environment* env = instruction->env()->DeepCopy(zone());
+  Environment* slow_path_env = env->DeepCopy(zone());
   // 1. Iterate the registers in the order they will be spilled to compute
   //    the slots they will be spilled to.
-  intptr_t next_slot = StackSize() + env->CountArgsPushed();
+  intptr_t next_slot = StackSize() + slow_path_env->CountArgsPushed();
   if (using_shared_stub) {
     // The PC from the call to the shared stub is pushed here.
     next_slot++;
   }
-  RegisterSet* regs = instruction->locs()->live_registers();
+  RegisterSet* regs = locs->live_registers();
   intptr_t fpu_reg_slots[kNumberOfFpuRegisters];
   intptr_t cpu_reg_slots[kNumberOfCpuRegisters];
   const intptr_t kFpuRegisterSpillFactor =
@@ -1005,14 +1001,14 @@
 
   // 2. Iterate the environment and replace register locations with the
   //    corresponding spill slot locations.
-  for (Environment::DeepIterator it(env); !it.Done(); it.Advance()) {
+  for (Environment::DeepIterator it(slow_path_env); !it.Done(); it.Advance()) {
     Location loc = it.CurrentLocation();
     Value* value = it.CurrentValue();
     it.SetCurrentLocation(LocationRemapForSlowPath(
         loc, value->definition(), cpu_reg_slots, fpu_reg_slots));
   }
 
-  return env;
+  return slow_path_env;
 }
 
 compiler::Label* FlowGraphCompiler::AddDeoptStub(intptr_t deopt_id,
@@ -1107,12 +1103,14 @@
 }
 
 void FlowGraphCompiler::FinalizeStackMaps(const Code& code) {
-  if (stackmap_table_builder_ == NULL) {
-    code.set_stackmaps(Object::null_array());
+  if (compressed_stackmaps_builder_ == NULL) {
+    code.set_compressed_stackmaps(
+        CompressedStackMaps::Handle(CompressedStackMaps::null()));
   } else {
-    // Finalize the stack map array and add it to the code object.
-    code.set_stackmaps(
-        Array::Handle(stackmap_table_builder_->FinalizeStackMaps(code)));
+    // Finalize the compressed stack maps and add it to the code object.
+    const auto& maps =
+        CompressedStackMaps::Handle(compressed_stackmaps_builder_->Finalize());
+    code.set_compressed_stackmaps(maps);
   }
 }
 
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.h b/runtime/vm/compiler/backend/flow_graph_compiler.h
index 4c26d2b..884bef3 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.h
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.h
@@ -791,7 +791,16 @@
   void ClobberDeadTempRegisters(LocationSummary* locs);
 #endif
 
-  Environment* SlowPathEnvironmentFor(Instruction* instruction,
+  // Returns a new environment based on [env] which accounts for the new
+  // locations of values in the slow path call.
+  Environment* SlowPathEnvironmentFor(Instruction* inst,
+                                      intptr_t num_slow_path_args) {
+    return SlowPathEnvironmentFor(inst->env(), inst->locs(),
+                                  num_slow_path_args);
+  }
+
+  Environment* SlowPathEnvironmentFor(Environment* env,
+                                      LocationSummary* locs,
                                       intptr_t num_slow_path_args);
 
   intptr_t CurrentTryIndex() const {
@@ -1025,11 +1034,11 @@
 
   intptr_t GetOptimizationThreshold() const;
 
-  StackMapTableBuilder* stackmap_table_builder() {
-    if (stackmap_table_builder_ == NULL) {
-      stackmap_table_builder_ = new StackMapTableBuilder();
+  CompressedStackMapsBuilder* compressed_stackmaps_builder() {
+    if (compressed_stackmaps_builder_ == NULL) {
+      compressed_stackmaps_builder_ = new CompressedStackMapsBuilder();
     }
-    return stackmap_table_builder_;
+    return compressed_stackmaps_builder_;
   }
 
 // TODO(vegorov) re-enable frame state tracking on DBC. It is
@@ -1091,7 +1100,7 @@
   BlockEntryInstr* current_block_;
   ExceptionHandlerList* exception_handlers_list_;
   DescriptorList* pc_descriptors_list_;
-  StackMapTableBuilder* stackmap_table_builder_;
+  CompressedStackMapsBuilder* compressed_stackmaps_builder_;
   CodeSourceMapBuilder* code_source_map_builder_;
   CatchEntryMovesMapBuilder* catch_entry_moves_maps_builder_;
   GrowableArray<BlockInfo*> block_info_;
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
index af3e2f5..8192b74 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_arm.cc
@@ -1373,8 +1373,17 @@
       ASSERT(destination.IsStackSlot());
       const intptr_t source_offset = source.ToStackSlotOffset();
       const intptr_t dest_offset = destination.ToStackSlotOffset();
-      __ LoadFromOffset(kWord, TMP, source.base_reg(), source_offset);
-      __ StoreToOffset(kWord, TMP, destination.base_reg(), dest_offset);
+
+      // LR not used by register allocator.
+      ASSERT(((1 << LR) & kDartAvailableCpuRegs) == 0);
+
+      // StoreToOffset uses TMP in the case where dest_offset is too large or
+      // small in order to calculate a new base. We fall back to using LR as a
+      // temporary as we know we're in a ParallelMove.
+      const Register temp_reg = LR;
+
+      __ LoadFromOffset(kWord, temp_reg, source.base_reg(), source_offset);
+      __ StoreToOffset(kWord, temp_reg, destination.base_reg(), dest_offset);
     }
   } else if (source.IsFpuRegister()) {
     if (destination.IsFpuRegister()) {
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
index 78987ee..bd3e251 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler_x64.cc
@@ -1379,6 +1379,7 @@
       __ movups(LocationToStackSlotAddress(destination), FpuTMP);
     }
   } else {
+    ASSERT(!source.IsInvalid());
     ASSERT(source.IsConstant());
     if (destination.IsFpuRegister() || destination.IsDoubleStackSlot()) {
       Register scratch = tmp->AllocateTemporary();
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 61eb977..671ebd3 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -932,6 +932,20 @@
   return kTagged;
 }
 
+Instruction* StoreInstanceFieldInstr::Canonicalize(FlowGraph* flow_graph) {
+  // Dart objects are allocated null-initialized, which means we can eliminate
+  // all initializing stores which store null value.
+  // TODO(dartbug.com/38454) Context objects can be allocated uninitialized
+  // as a performance optimization (all initializing stores are inlined into
+  // the caller, which allocates the context). Investigate if this can be
+  // changed to align with normal Dart objects for code size reasons.
+  if (is_initialization_ && slot().IsDartField() &&
+      value()->BindsToConstantNull()) {
+    return nullptr;
+  }
+  return this;
+}
+
 bool GuardFieldClassInstr::AttributesEqual(Instruction* other) const {
   return field().raw() == other->AsGuardFieldClass()->field().raw();
 }
@@ -1440,6 +1454,15 @@
   }
 }
 
+void Instruction::RepairPushArgsInEnvironment() const {
+  const intptr_t arg_count = ArgumentCount();
+  ASSERT(arg_count <= env()->Length());
+  const intptr_t env_base = env()->Length() - arg_count;
+  for (intptr_t i = 0; i < arg_count; ++i) {
+    env()->ValueAt(env_base + i)->BindToEnvironment(PushArgumentAt(i));
+  }
+}
+
 void Instruction::InheritDeoptTargetAfter(FlowGraph* flow_graph,
                                           Definition* call,
                                           Definition* result) {
@@ -2780,6 +2803,8 @@
     case Slot::Kind::kCapturedVariable:
     case Slot::Kind::kDartField:
     case Slot::Kind::kPointer_c_memory_address:
+    case Slot::Kind::kType_arguments:
+    case Slot::Kind::kTypeArgumentsIndex:
       return false;
   }
   UNREACHABLE();
@@ -4082,7 +4107,16 @@
   // (As opposed to here where we don't check for the return value of
   // [Intrinsify]).
   const Function& function = compiler->parsed_function().function();
-  if (function.IsDynamicFunction()) {
+
+  // For functions which need an args descriptor the switchable call sites will
+  // transition directly to calling via a stub (and therefore never call the
+  // monomorphic entry).
+  //
+  // See runtime_entry.cc:DEFINE_RUNTIME_ENTRY(UnlinkedCall)
+  const bool needs_args_descriptor =
+      function.HasOptionalParameters() || function.IsGeneric();
+
+  if (function.IsDynamicFunction() && !needs_args_descriptor) {
     compiler->SpecialStatsBegin(CombinedCodeStatistics::kTagCheckedEntry);
     if (!FLAG_precompiled_mode) {
       __ MonomorphicCheckedEntryJIT();
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 7d13712..e2e8ac3 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -805,6 +805,9 @@
   }
   inline Definition* ArgumentAt(intptr_t index) const;
 
+  // Repairs trailing PushArgs in environment.
+  void RepairPushArgsInEnvironment() const;
+
   // Returns true, if this instruction can deoptimize with its current inputs.
   // This property can change if we add or remove redefinitions that constrain
   // the type or the range of input operands during compilation.
@@ -4699,6 +4702,8 @@
 
   virtual Representation RequiredInputRepresentation(intptr_t index) const;
 
+  virtual Instruction* Canonicalize(FlowGraph* flow_graph);
+
   PRINT_OPERANDS_TO_SUPPORT
   ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
   ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
@@ -7992,8 +7997,10 @@
            from == kUnboxedInt32 || from == kUntagged);
     ASSERT(to == kUnboxedInt64 || to == kUnboxedUint32 || to == kUnboxedInt32 ||
            to == kUntagged);
-    ASSERT(from != kUntagged || to == kUnboxedIntPtr);
-    ASSERT(to != kUntagged || from == kUnboxedIntPtr);
+    ASSERT(from != kUntagged ||
+           (to == kUnboxedIntPtr || to == kUnboxedFfiIntPtr));
+    ASSERT(to != kUntagged ||
+           (from == kUnboxedIntPtr || from == kUnboxedFfiIntPtr));
     SetInputAt(0, value);
   }
 
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 348ade2..8a986f7 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -3671,13 +3671,20 @@
   static constexpr intptr_t kNumSlowPathArgs = 2;
 
   CheckedSmiComparisonSlowPath(CheckedSmiComparisonInstr* instruction,
+                               Environment* env,
                                intptr_t try_index,
                                BranchLabels labels,
                                bool merged)
       : TemplateSlowPathCode(instruction),
         try_index_(try_index),
         labels_(labels),
-        merged_(merged) {}
+        merged_(merged),
+        env_(env) {
+    // The environment must either come from the comparison or the environment
+    // was cleared from the comparison (and moved to a branch).
+    ASSERT(env == instruction->env() ||
+           (merged && instruction->env() == nullptr));
+  }
 
   virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
     if (compiler::Assembler::EmittingComments()) {
@@ -3689,10 +3696,9 @@
     locs->live_registers()->Remove(Location::RegisterLocation(result));
 
     compiler->SaveLiveRegisters(locs);
-    if (instruction()->env() != NULL) {
-      Environment* env =
-          compiler->SlowPathEnvironmentFor(instruction(), kNumSlowPathArgs);
-      compiler->pending_deoptimization_env_ = env;
+    if (env_ != nullptr) {
+      compiler->pending_deoptimization_env_ =
+          compiler->SlowPathEnvironmentFor(env_, locs, kNumSlowPathArgs);
     }
     __ Push(locs->in(0).reg());
     __ Push(locs->in(1).reg());
@@ -3704,7 +3710,7 @@
         instruction()->token_pos(), locs, try_index_, kNumSlowPathArgs);
     __ mov(result, compiler::Operand(R0));
     compiler->RestoreLiveRegisters(locs);
-    compiler->pending_deoptimization_env_ = NULL;
+    compiler->pending_deoptimization_env_ = nullptr;
     if (merged_) {
       __ CompareObject(result, Bool::True());
       __ b(instruction()->is_negated() ? labels_.false_label
@@ -3727,6 +3733,7 @@
   intptr_t try_index_;
   BranchLabels labels_;
   bool merged_;
+  Environment* env_;
 };
 
 LocationSummary* CheckedSmiComparisonInstr::MakeLocationSummary(
@@ -3771,7 +3778,7 @@
                                                BranchInstr* branch) {
   BranchLabels labels = compiler->CreateBranchLabels(branch);
   CheckedSmiComparisonSlowPath* slow_path = new CheckedSmiComparisonSlowPath(
-      this, compiler->CurrentTryIndex(), labels,
+      this, branch->env(), compiler->CurrentTryIndex(), labels,
       /* merged = */ true);
   compiler->AddSlowPathCode(slow_path);
   EMIT_SMI_CHECK;
@@ -3784,7 +3791,7 @@
 void CheckedSmiComparisonInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   BranchLabels labels = {NULL, NULL, NULL};
   CheckedSmiComparisonSlowPath* slow_path = new CheckedSmiComparisonSlowPath(
-      this, compiler->CurrentTryIndex(), labels,
+      this, env(), compiler->CurrentTryIndex(), labels,
       /* merged = */ false);
   compiler->AddSlowPathCode(slow_path);
   EMIT_SMI_CHECK;
@@ -6864,8 +6871,10 @@
   LocationSummary* summary = new (zone)
       LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
   if (from() == kUntagged || to() == kUntagged) {
-    ASSERT((from() == kUntagged && to() == kUnboxedIntPtr) ||
-           (from() == kUnboxedIntPtr && to() == kUntagged));
+    ASSERT((from() == kUntagged && to() == kUnboxedInt32) ||
+           (from() == kUntagged && to() == kUnboxedUint32) ||
+           (from() == kUnboxedInt32 && to() == kUntagged) ||
+           (from() == kUnboxedUint32 && to() == kUntagged));
     ASSERT(!CanDeoptimize());
     summary->set_in(0, Location::RequiresRegister());
     summary->set_out(0, Location::SameAsFirstInput());
diff --git a/runtime/vm/compiler/backend/il_arm64.cc b/runtime/vm/compiler/backend/il_arm64.cc
index 2f8a4db..1d934ec 100644
--- a/runtime/vm/compiler/backend/il_arm64.cc
+++ b/runtime/vm/compiler/backend/il_arm64.cc
@@ -990,7 +990,7 @@
   __ PopNativeCalleeSavedRegisters();
 
 #if defined(TARGET_OS_FUCHSIA)
-  UNREACHABLE(); // Fuchsia does not allow dart:ffi.
+  UNREACHABLE();  // Fuchsia does not allow dart:ffi.
 #elif defined(USING_SHADOW_CALL_STACK)
 #error Unimplemented
 #endif
@@ -1051,7 +1051,7 @@
   __ PushImmediate(0);
 
 #if defined(TARGET_OS_FUCHSIA)
-  UNREACHABLE(); // Fuchsia does not allow dart:ffi.
+  UNREACHABLE();  // Fuchsia does not allow dart:ffi.
 #elif defined(USING_SHADOW_CALL_STACK)
 #error Unimplemented
 #endif
@@ -1335,7 +1335,7 @@
 LocationSummary* LoadIndexedInstr::MakeLocationSummary(Zone* zone,
                                                        bool opt) const {
   const intptr_t kNumInputs = 2;
-  const intptr_t kNumTemps = aligned() ? 0 : 1;
+  const intptr_t kNumTemps = 0;
   LocationSummary* locs = new (zone)
       LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
   locs->set_in(0, Location::RequiresRegister());
@@ -1352,9 +1352,6 @@
   } else {
     locs->set_out(0, Location::RequiresRegister());
   }
-  if (!aligned()) {
-    locs->set_temp(0, Location::RequiresRegister());
-  }
   return locs;
 }
 
@@ -1362,32 +1359,16 @@
   // The array register points to the backing store for external arrays.
   const Register array = locs()->in(0).reg();
   const Location index = locs()->in(1);
-  const Register address = aligned() ? kNoRegister : locs()->temp(0).reg();
 
   compiler::Address element_address(TMP);  // Bad address.
-  if (aligned()) {
-    element_address =
-        index.IsRegister()
-            ? __ ElementAddressForRegIndex(true,  // Load.
-                                           IsExternal(), class_id(),
-                                           index_scale(), array, index.reg())
-            : __ ElementAddressForIntIndex(IsExternal(), class_id(),
-                                           index_scale(), array,
-                                           Smi::Cast(index.constant()).Value());
-    // Warning: element_address may use register TMP as base.
-  } else {
-    if (index.IsRegister()) {
-      __ LoadElementAddressForRegIndex(address,
-                                       true,  // Load.
-                                       IsExternal(), class_id(), index_scale(),
-                                       array, index.reg());
-    } else {
-      __ LoadElementAddressForIntIndex(address, IsExternal(), class_id(),
-                                       index_scale(), array,
-                                       Smi::Cast(index.constant()).Value());
-    }
-  }
-
+  element_address =
+      index.IsRegister()
+          ? __ ElementAddressForRegIndex(true,  // Load.
+                                         IsExternal(), class_id(),
+                                         index_scale(), array, index.reg())
+          : __ ElementAddressForIntIndex(IsExternal(), class_id(),
+                                         index_scale(), array,
+                                         Smi::Cast(index.constant()).Value());
   if ((representation() == kUnboxedDouble) ||
       (representation() == kUnboxedFloat32x4) ||
       (representation() == kUnboxedInt32x4) ||
@@ -1396,26 +1377,15 @@
     switch (class_id()) {
       case kTypedDataFloat32ArrayCid:
         // Load single precision float.
-        if (aligned()) {
-          __ fldrs(result, element_address);
-        } else {
-          __ LoadUnaligned(TMP, address, TMP2, kUnsignedWord);
-          __ fmovsr(result, TMP);
-        }
+        __ fldrs(result, element_address);
         break;
       case kTypedDataFloat64ArrayCid:
         // Load double precision float.
-        if (aligned()) {
-          __ fldrd(result, element_address);
-        } else {
-          __ LoadUnaligned(TMP, address, TMP2, kDoubleWord);
-          __ fmovdr(result, TMP);
-        }
+        __ fldrd(result, element_address);
         break;
       case kTypedDataFloat64x2ArrayCid:
       case kTypedDataInt32x4ArrayCid:
       case kTypedDataFloat32x4ArrayCid:
-        ASSERT(aligned());
         __ fldrq(result, element_address);
         break;
       default:
@@ -1428,28 +1398,16 @@
   switch (class_id()) {
     case kTypedDataInt32ArrayCid:
       ASSERT(representation() == kUnboxedInt32);
-      if (aligned()) {
-        __ ldr(result, element_address, kWord);
-      } else {
-        __ LoadUnaligned(result, address, TMP, kWord);
-      }
+      __ ldr(result, element_address, kWord);
       break;
     case kTypedDataUint32ArrayCid:
       ASSERT(representation() == kUnboxedUint32);
-      if (aligned()) {
-        __ ldr(result, element_address, kUnsignedWord);
-      } else {
-        __ LoadUnaligned(result, address, TMP, kUnsignedWord);
-      }
+      __ ldr(result, element_address, kUnsignedWord);
       break;
     case kTypedDataInt64ArrayCid:
     case kTypedDataUint64ArrayCid:
       ASSERT(representation() == kUnboxedInt64);
-      if (aligned()) {
-        __ ldr(result, element_address, kDoubleWord);
-      } else {
-        __ LoadUnaligned(result, address, TMP, kDoubleWord);
-      }
+      __ ldr(result, element_address, kDoubleWord);
       break;
     case kTypedDataInt8ArrayCid:
       ASSERT(representation() == kUnboxedIntPtr);
@@ -1468,26 +1426,17 @@
       break;
     case kTypedDataInt16ArrayCid:
       ASSERT(representation() == kUnboxedIntPtr);
-      if (aligned()) {
-        __ ldr(result, element_address, kHalfword);
-      } else {
-        __ LoadUnaligned(result, address, TMP, kHalfword);
-      }
+      __ ldr(result, element_address, kHalfword);
       break;
     case kTypedDataUint16ArrayCid:
     case kTwoByteStringCid:
     case kExternalTwoByteStringCid:
       ASSERT(representation() == kUnboxedIntPtr);
-      if (aligned()) {
-        __ ldr(result, element_address, kUnsignedHalfword);
-      } else {
-        __ LoadUnaligned(result, address, TMP, kUnsignedHalfword);
-      }
+      __ ldr(result, element_address, kUnsignedHalfword);
       break;
     default:
       ASSERT(representation() == kTagged);
       ASSERT((class_id() == kArrayCid) || (class_id() == kImmutableArrayCid));
-      ASSERT(aligned());
       __ ldr(result, element_address);
       break;
   }
@@ -1509,10 +1458,7 @@
   // The string register points to the backing store for external strings.
   const Register str = locs()->in(0).reg();
   const Location index = locs()->in(1);
-
-  compiler::Address element_address = __ ElementAddressForRegIndex(
-      true, IsExternal(), class_id(), index_scale(), str, index.reg());
-  // Warning: element_address may use register TMP as base.
+  OperandSize sz = OperandSize::kByte;
 
   Register result = locs()->out(0).reg();
   switch (class_id()) {
@@ -1520,37 +1466,41 @@
     case kExternalOneByteStringCid:
       switch (element_count()) {
         case 1:
-          __ ldr(result, element_address, kUnsignedByte);
+          sz = kUnsignedByte;
           break;
         case 2:
-          __ ldr(result, element_address, kUnsignedHalfword);
+          sz = kUnsignedHalfword;
           break;
         case 4:
-          __ ldr(result, element_address, kUnsignedWord);
+          sz = kUnsignedWord;
           break;
         default:
           UNREACHABLE();
       }
-      __ SmiTag(result);
       break;
     case kTwoByteStringCid:
     case kExternalTwoByteStringCid:
       switch (element_count()) {
         case 1:
-          __ ldr(result, element_address, kUnsignedHalfword);
+          sz = kUnsignedHalfword;
           break;
         case 2:
-          __ ldr(result, element_address, kUnsignedWord);
+          sz = kUnsignedWord;
           break;
         default:
           UNREACHABLE();
       }
-      __ SmiTag(result);
       break;
     default:
       UNREACHABLE();
       break;
   }
+  // Warning: element_address may use register TMP as base.
+  compiler::Address element_address = __ ElementAddressForRegIndexWithSize(
+      true, IsExternal(), class_id(), sz, index_scale(), str, index.reg());
+  __ ldr(result, element_address, sz);
+
+  __ SmiTag(result);
 }
 
 Representation StoreIndexedInstr::RequiredInputRepresentation(
@@ -1596,7 +1546,7 @@
 LocationSummary* StoreIndexedInstr::MakeLocationSummary(Zone* zone,
                                                         bool opt) const {
   const intptr_t kNumInputs = 3;
-  const intptr_t kNumTemps = aligned() ? 1 : 2;
+  const intptr_t kNumTemps = 1;
   LocationSummary* locs = new (zone)
       LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
   locs->set_in(0, Location::RequiresRegister());
@@ -1605,9 +1555,7 @@
   } else {
     locs->set_in(1, Location::WritableRegister());
   }
-  for (intptr_t i = 0; i < kNumTemps; i++) {
-    locs->set_temp(i, Location::RequiresRegister());
-  }
+  locs->set_temp(0, Location::RequiresRegister());
 
   switch (class_id()) {
     case kArrayCid:
@@ -1654,7 +1602,6 @@
   const Register array = locs()->in(0).reg();
   const Location index = locs()->in(1);
   const Register address = locs()->temp(0).reg();
-  const Register scratch = aligned() ? kNoRegister : locs()->temp(1).reg();
 
   if (index.IsRegister()) {
     __ LoadElementAddressForRegIndex(address,
@@ -1669,7 +1616,6 @@
 
   switch (class_id()) {
     case kArrayCid:
-      ASSERT(aligned());
       if (ShouldEmitStoreBarrier()) {
         const Register value = locs()->in(2).reg();
         __ StoreIntoArray(array, address, value, CanValueBeSmi(),
@@ -1688,7 +1634,6 @@
     case kExternalTypedDataUint8ArrayCid:
     case kOneByteStringCid: {
       ASSERT(RequiredInputRepresentation(2) == kUnboxedIntPtr);
-      ASSERT(aligned());
       if (locs()->in(2).IsConstant()) {
         const Smi& constant = Smi::Cast(locs()->in(2).constant());
         __ LoadImmediate(TMP, static_cast<int8_t>(constant.Value()));
@@ -1702,7 +1647,6 @@
     case kTypedDataUint8ClampedArrayCid:
     case kExternalTypedDataUint8ClampedArrayCid: {
       ASSERT(RequiredInputRepresentation(2) == kUnboxedIntPtr);
-      ASSERT(aligned());
       if (locs()->in(2).IsConstant()) {
         const Smi& constant = Smi::Cast(locs()->in(2).constant());
         intptr_t value = constant.Value();
@@ -1728,57 +1672,34 @@
     case kTypedDataUint16ArrayCid: {
       ASSERT(RequiredInputRepresentation(2) == kUnboxedIntPtr);
       const Register value = locs()->in(2).reg();
-      if (aligned()) {
-        __ str(value, compiler::Address(address), kUnsignedHalfword);
-      } else {
-        __ StoreUnaligned(value, address, scratch, kUnsignedHalfword);
-      }
+      __ str(value, compiler::Address(address), kUnsignedHalfword);
       break;
     }
     case kTypedDataInt32ArrayCid:
     case kTypedDataUint32ArrayCid: {
       const Register value = locs()->in(2).reg();
-      if (aligned()) {
-        __ str(value, compiler::Address(address), kUnsignedWord);
-      } else {
-        __ StoreUnaligned(value, address, scratch, kUnsignedWord);
-      }
+      __ str(value, compiler::Address(address), kUnsignedWord);
       break;
     }
     case kTypedDataInt64ArrayCid:
     case kTypedDataUint64ArrayCid: {
       const Register value = locs()->in(2).reg();
-      if (aligned()) {
-        __ str(value, compiler::Address(address), kDoubleWord);
-      } else {
-        __ StoreUnaligned(value, address, scratch, kDoubleWord);
-      }
+      __ str(value, compiler::Address(address), kDoubleWord);
       break;
     }
     case kTypedDataFloat32ArrayCid: {
       const VRegister value_reg = locs()->in(2).fpu_reg();
-      if (aligned()) {
-        __ fstrs(value_reg, compiler::Address(address));
-      } else {
-        __ fmovrs(TMP, value_reg);
-        __ StoreUnaligned(TMP, address, scratch, kWord);
-      }
+      __ fstrs(value_reg, compiler::Address(address));
       break;
     }
     case kTypedDataFloat64ArrayCid: {
       const VRegister value_reg = locs()->in(2).fpu_reg();
-      if (aligned()) {
-        __ fstrd(value_reg, compiler::Address(address));
-      } else {
-        __ fmovrd(TMP, value_reg);
-        __ StoreUnaligned(TMP, address, scratch, kDoubleWord);
-      }
+      __ fstrd(value_reg, compiler::Address(address));
       break;
     }
     case kTypedDataFloat64x2ArrayCid:
     case kTypedDataInt32x4ArrayCid:
     case kTypedDataFloat32x4ArrayCid: {
-      ASSERT(aligned());
       const VRegister value_reg = locs()->in(2).fpu_reg();
       __ fstrq(value_reg, compiler::Address(address));
       break;
@@ -3281,13 +3202,20 @@
   static constexpr intptr_t kNumSlowPathArgs = 2;
 
   CheckedSmiComparisonSlowPath(CheckedSmiComparisonInstr* instruction,
+                               Environment* env,
                                intptr_t try_index,
                                BranchLabels labels,
                                bool merged)
       : TemplateSlowPathCode(instruction),
         try_index_(try_index),
         labels_(labels),
-        merged_(merged) {}
+        merged_(merged),
+        env_(env) {
+    // The environment must either come from the comparison or the environment
+    // was cleared from the comparison (and moved to a branch).
+    ASSERT(env == instruction->env() ||
+           (merged && instruction->env() == nullptr));
+  }
 
   virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
     if (compiler::Assembler::EmittingComments()) {
@@ -3299,10 +3227,9 @@
     locs->live_registers()->Remove(Location::RegisterLocation(result));
 
     compiler->SaveLiveRegisters(locs);
-    if (instruction()->env() != NULL) {
-      Environment* env =
-          compiler->SlowPathEnvironmentFor(instruction(), kNumSlowPathArgs);
-      compiler->pending_deoptimization_env_ = env;
+    if (env_ != nullptr) {
+      compiler->pending_deoptimization_env_ =
+          compiler->SlowPathEnvironmentFor(env_, locs, kNumSlowPathArgs);
     }
     __ Push(locs->in(0).reg());
     __ Push(locs->in(1).reg());
@@ -3314,7 +3241,7 @@
         instruction()->token_pos(), locs, try_index_, kNumSlowPathArgs);
     __ mov(result, R0);
     compiler->RestoreLiveRegisters(locs);
-    compiler->pending_deoptimization_env_ = NULL;
+    compiler->pending_deoptimization_env_ = nullptr;
     if (merged_) {
       __ CompareObject(result, Bool::True());
       __ b(instruction()->is_negated() ? labels_.false_label
@@ -3333,6 +3260,7 @@
   intptr_t try_index_;
   BranchLabels labels_;
   bool merged_;
+  Environment* env_;
 };
 
 LocationSummary* CheckedSmiComparisonInstr::MakeLocationSummary(
@@ -3376,7 +3304,7 @@
                                                BranchInstr* branch) {
   BranchLabels labels = compiler->CreateBranchLabels(branch);
   CheckedSmiComparisonSlowPath* slow_path = new CheckedSmiComparisonSlowPath(
-      this, compiler->CurrentTryIndex(), labels,
+      this, branch->env(), compiler->CurrentTryIndex(), labels,
       /* merged = */ true);
   compiler->AddSlowPathCode(slow_path);
   EMIT_SMI_CHECK;
@@ -3397,7 +3325,7 @@
   // For this purpose, 'merged' slow path is generated: it tests
   // result of a call and jumps directly to true or false label.
   CheckedSmiComparisonSlowPath* slow_path = new CheckedSmiComparisonSlowPath(
-      this, compiler->CurrentTryIndex(), labels,
+      this, env(), compiler->CurrentTryIndex(), labels,
       /* merged = */ is_negated());
   compiler->AddSlowPathCode(slow_path);
   EMIT_SMI_CHECK;
diff --git a/runtime/vm/compiler/backend/il_deserializer.cc b/runtime/vm/compiler/backend/il_deserializer.cc
index 97a98b1..d66ce30 100644
--- a/runtime/vm/compiler/backend/il_deserializer.cc
+++ b/runtime/vm/compiler/backend/il_deserializer.cc
@@ -2137,6 +2137,9 @@
     case Slot::Kind::kTypeArguments:
       *out = &Slot::GetTypeArgumentsSlotAt(thread(), offset);
       break;
+    case Slot::Kind::kTypeArgumentsIndex:
+      *out = &Slot::GetTypeArgumentsIndexSlot(thread(), offset);
+      break;
     case Slot::Kind::kCapturedVariable:
       StoreError(kind_sexp, "unhandled Slot kind");
       return false;
diff --git a/runtime/vm/compiler/backend/il_ia32.cc b/runtime/vm/compiler/backend/il_ia32.cc
index a05e810..b6daf52 100644
--- a/runtime/vm/compiler/backend/il_ia32.cc
+++ b/runtime/vm/compiler/backend/il_ia32.cc
@@ -198,7 +198,7 @@
   __ popl(EBX);
 
 #if defined(TARGET_OS_FUCHSIA)
-  UNREACHABLE(); // Fuchsia does not allow dart:ffi.
+  UNREACHABLE();  // Fuchsia does not allow dart:ffi.
 #elif defined(USING_SHADOW_CALL_STACK)
 #error Unimplemented
 #endif
@@ -1037,7 +1037,7 @@
   __ pushl(EAX);
 
 #if defined(TARGET_OS_FUCHSIA)
-  UNREACHABLE(); // Fuchsia does not allow dart:ffi.
+  UNREACHABLE();  // Fuchsia does not allow dart:ffi.
 #elif defined(USING_SHADOW_CALL_STACK)
 #error Unimplemented
 #endif
@@ -6123,8 +6123,10 @@
       LocationSummary(zone, kNumInputs, kNumTemps, LocationSummary::kNoCall);
 
   if (from() == kUntagged || to() == kUntagged) {
-    ASSERT((from() == kUntagged && to() == kUnboxedIntPtr) ||
-           (from() == kUnboxedIntPtr && to() == kUntagged));
+    ASSERT((from() == kUntagged && to() == kUnboxedInt32) ||
+           (from() == kUntagged && to() == kUnboxedUint32) ||
+           (from() == kUnboxedInt32 && to() == kUntagged) ||
+           (from() == kUnboxedUint32 && to() == kUntagged));
     ASSERT(!CanDeoptimize());
     summary->set_in(0, Location::RequiresRegister());
     summary->set_out(0, Location::SameAsFirstInput());
@@ -6153,8 +6155,10 @@
 
 void IntConverterInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
   const bool is_nop_conversion =
-      (from() == kUntagged && to() == kUnboxedIntPtr) ||
-      (from() == kUnboxedIntPtr && to() == kUntagged);
+      (from() == kUntagged && to() == kUnboxedInt32) ||
+      (from() == kUntagged && to() == kUnboxedUint32) ||
+      (from() == kUnboxedInt32 && to() == kUntagged) ||
+      (from() == kUnboxedUint32 && to() == kUntagged);
   if (is_nop_conversion) {
     ASSERT(locs()->in(0).reg() == locs()->out(0).reg());
     return;
diff --git a/runtime/vm/compiler/backend/il_serializer.cc b/runtime/vm/compiler/backend/il_serializer.cc
index 71844b7..2be7442 100644
--- a/runtime/vm/compiler/backend/il_serializer.cc
+++ b/runtime/vm/compiler/backend/il_serializer.cc
@@ -1401,10 +1401,23 @@
   }
 }
 
+// TODO(@sstrickl): find a better way, store stack index?
+static intptr_t CountArgs(Environment* env) {
+  if (env != nullptr) {
+    intptr_t arg_count = CountArgs(env->outer());
+    for (intptr_t i = 0, n = env->Length(); i < n; ++i) {
+      if (env->ValueAt(i)->definition()->IsPushArgument()) {
+        arg_count++;
+      }
+    }
+    return arg_count;
+  }
+  return 0;
+}
+
 SExpression* Environment::ToSExpression(FlowGraphSerializer* s) const {
   auto sexp = new (s->zone()) SExpList(s->zone());
-  intptr_t arg_count = 0;
-
+  intptr_t arg_count = CountArgs(outer_);
   for (intptr_t i = 0; i < values_.length(); ++i) {
     if (values_[i]->definition()->IsPushArgument()) {
       s->AddSymbol(sexp, OS::SCreate(s->zone(), "a%" Pd "", arg_count++));
diff --git a/runtime/vm/compiler/backend/il_x64.cc b/runtime/vm/compiler/backend/il_x64.cc
index 0e3b73e..dc394bf 100644
--- a/runtime/vm/compiler/backend/il_x64.cc
+++ b/runtime/vm/compiler/backend/il_x64.cc
@@ -171,7 +171,7 @@
                   CallingConventions::kCalleeSaveXmmRegisters);
 
 #if defined(TARGET_OS_FUCHSIA)
-  UNREACHABLE(); // Fuchsia does not allow dart:ffi.
+  UNREACHABLE();  // Fuchsia does not allow dart:ffi.
 #elif defined(USING_SHADOW_CALL_STACK)
 #error Unimplemented
 #endif
@@ -1037,7 +1037,7 @@
   __ EnterFrame(0);
 
 #if defined(TARGET_OS_FUCHSIA)
-  UNREACHABLE(); // Fuchsia does not allow dart:ffi.
+  UNREACHABLE();  // Fuchsia does not allow dart:ffi.
 #elif defined(USING_SHADOW_CALL_STACK)
 #error Unimplemented
 #endif
@@ -3336,13 +3336,20 @@
   static constexpr intptr_t kNumSlowPathArgs = 2;
 
   CheckedSmiComparisonSlowPath(CheckedSmiComparisonInstr* instruction,
+                               Environment* env,
                                intptr_t try_index,
                                BranchLabels labels,
                                bool merged)
       : TemplateSlowPathCode(instruction),
         try_index_(try_index),
         labels_(labels),
-        merged_(merged) {}
+        merged_(merged),
+        env_(env) {
+    // The environment must either come from the comparison or the environment
+    // was cleared from the comparison (and moved to a branch).
+    ASSERT(env == instruction->env() ||
+           (merged && instruction->env() == nullptr));
+  }
 
   virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
     if (compiler::Assembler::EmittingComments()) {
@@ -3354,10 +3361,9 @@
     locs->live_registers()->Remove(Location::RegisterLocation(result));
 
     compiler->SaveLiveRegisters(locs);
-    if (instruction()->env() != NULL) {
-      Environment* env =
-          compiler->SlowPathEnvironmentFor(instruction(), kNumSlowPathArgs);
-      compiler->pending_deoptimization_env_ = env;
+    if (env_ != nullptr) {
+      compiler->pending_deoptimization_env_ =
+          compiler->SlowPathEnvironmentFor(env_, locs, kNumSlowPathArgs);
     }
     __ pushq(locs->in(0).reg());
     __ pushq(locs->in(1).reg());
@@ -3371,7 +3377,7 @@
         instruction()->token_pos(), locs, try_index_, kNumSlowPathArgs);
     __ MoveRegister(result, RAX);
     compiler->RestoreLiveRegisters(locs);
-    compiler->pending_deoptimization_env_ = NULL;
+    compiler->pending_deoptimization_env_ = nullptr;
     if (merged_) {
       __ CompareObject(result, Bool::True());
       __ j(EQUAL, instruction()->is_negated() ? labels_.false_label
@@ -3389,6 +3395,7 @@
   intptr_t try_index_;
   BranchLabels labels_;
   bool merged_;
+  Environment* env_;
 };
 
 LocationSummary* CheckedSmiComparisonInstr::MakeLocationSummary(
@@ -3433,7 +3440,7 @@
                                                BranchInstr* branch) {
   BranchLabels labels = compiler->CreateBranchLabels(branch);
   CheckedSmiComparisonSlowPath* slow_path = new CheckedSmiComparisonSlowPath(
-      this, compiler->CurrentTryIndex(), labels,
+      this, branch->env(), compiler->CurrentTryIndex(), labels,
       /* merged = */ true);
   compiler->AddSlowPathCode(slow_path);
   EMIT_SMI_CHECK;
@@ -3454,7 +3461,7 @@
   // For this purpose, 'merged' slow path is generated: it tests
   // result of a call and jumps directly to true or false label.
   CheckedSmiComparisonSlowPath* slow_path = new CheckedSmiComparisonSlowPath(
-      this, compiler->CurrentTryIndex(), labels,
+      this, env(), compiler->CurrentTryIndex(), labels,
       /* merged = */ is_negated());
   compiler->AddSlowPathCode(slow_path);
   EMIT_SMI_CHECK;
diff --git a/runtime/vm/compiler/backend/inliner.cc b/runtime/vm/compiler/backend/inliner.cc
index 2a18c66..d171a71 100644
--- a/runtime/vm/compiler/backend/inliner.cc
+++ b/runtime/vm/compiler/backend/inliner.cc
@@ -2081,8 +2081,9 @@
                                              fallback_call);
     AppendInstruction(AppendInstruction(cursor, fallback_call),
                       fallback_return);
+    fallback_call->RepairPushArgsInEnvironment();
     exit_collector_->AddExit(fallback_return);
-    cursor = NULL;
+    cursor = nullptr;
   } else {
     // Remove push arguments of the call.
     for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) {
diff --git a/runtime/vm/compiler/backend/linearscan.cc b/runtime/vm/compiler/backend/linearscan.cc
index b196088..efce8fa 100644
--- a/runtime/vm/compiler/backend/linearscan.cc
+++ b/runtime/vm/compiler/backend/linearscan.cc
@@ -1151,6 +1151,8 @@
       live_registers->Add(*in_ref, range->representation());
     }
     MoveOperands* move = AddMoveAt(pos - 1, *in_ref, Location::Any());
+    ASSERT(!in_ref->IsRegister() ||
+           ((1 << in_ref->reg()) & kDartAvailableCpuRegs) != 0);
     BlockLocation(*in_ref, pos - 1, pos + 1);
     range->AddUseInterval(block->start_pos(), pos - 1);
     range->AddHintedUse(pos - 1, move->src_slot(), in_ref);
@@ -1217,6 +1219,8 @@
     //    register        [--)
     //    output             [-------
     //
+    ASSERT(!out->IsRegister() ||
+           ((1 << out->reg()) & kDartAvailableCpuRegs) != 0);
     BlockLocation(*out, pos, pos + 1);
 
     if (range->vreg() == kTempVirtualRegister) return;
@@ -1420,6 +1424,8 @@
     // We do not support pair locations for temporaries.
     ASSERT(!temp.IsPairLocation());
     if (temp.IsMachineRegister()) {
+      ASSERT(!temp.IsRegister() ||
+             ((1 << temp.reg()) & kDartAvailableCpuRegs) != 0);
       BlockLocation(temp, pos, pos + 1);
     } else if (temp.IsUnallocated()) {
       LiveRange* range = MakeLiveRangeForTemporary();
diff --git a/runtime/vm/compiler/backend/locations.cc b/runtime/vm/compiler/backend/locations.cc
index 9593b66..37b17c7 100644
--- a/runtime/vm/compiler/backend/locations.cc
+++ b/runtime/vm/compiler/backend/locations.cc
@@ -118,6 +118,7 @@
 }
 
 Location LocationFixedRegisterOrConstant(Value* value, Register reg) {
+  ASSERT(((1 << reg) & kDartAvailableCpuRegs) != 0);
   ConstantInstr* constant = value->definition()->AsConstant();
   return ((constant != NULL) && compiler::Assembler::IsSafe(constant->value()))
              ? Location::Constant(constant)
@@ -125,6 +126,7 @@
 }
 
 Location LocationFixedRegisterOrSmiConstant(Value* value, Register reg) {
+  ASSERT(((1 << reg) & kDartAvailableCpuRegs) != 0);
   ConstantInstr* constant = value->definition()->AsConstant();
   return ((constant != NULL) &&
           compiler::Assembler::IsSafeSmi(constant->value()))
diff --git a/runtime/vm/compiler/backend/range_analysis.cc b/runtime/vm/compiler/backend/range_analysis.cc
index 84e1557..52aee67 100644
--- a/runtime/vm/compiler/backend/range_analysis.cc
+++ b/runtime/vm/compiler/backend/range_analysis.cc
@@ -2670,6 +2670,8 @@
     case Slot::Kind::kPointer_c_memory_address:
     case Slot::Kind::kTypedDataBase_data_field:
     case Slot::Kind::kTypedDataView_data:
+    case Slot::Kind::kType_arguments:
+    case Slot::Kind::kTypeArgumentsIndex:
       // Not an integer valued field.
       UNREACHABLE();
       break;
@@ -2771,6 +2773,7 @@
     case kUnboxedInt32:
       return RangeBoundary::kRangeBoundaryInt32;
     case kUnboxedInt64:
+    case kUnboxedUint32:  // Overapproximate Uint32 as Int64.
       return RangeBoundary::kRangeBoundaryInt64;
     default:
       UNREACHABLE();
diff --git a/runtime/vm/compiler/backend/redundancy_elimination.cc b/runtime/vm/compiler/backend/redundancy_elimination.cc
index d8300e8..0155377 100644
--- a/runtime/vm/compiler/backend/redundancy_elimination.cc
+++ b/runtime/vm/compiler/backend/redundancy_elimination.cc
@@ -478,11 +478,22 @@
     if ((index_constant != NULL) && index_constant->value().IsSmi()) {
       const intptr_t index_value = Smi::Cast(index_constant->value()).Value();
       const ElementSize size = ElementSizeFor(class_id);
-      const bool is_typed_data = (size != kNoSize);
+      const bool is_typed_access = (size != kNoSize);
+      // Indexing into [RawTypedDataView]/[RawExternalTypedData happens via a
+      // untagged load of the `_data` field (which points to C memory).
+      //
+      // Indexing into dart:ffi's [RawPointer] happens via loading of the
+      // `c_memory_address_`, converting it to an integer, doing some arithmetic
+      // and finally using IntConverterInstr to convert to a untagged
+      // representation.
+      //
+      // In both cases the array used for load/store has untagged
+      // representation.
+      const bool can_be_view = instance_->representation() == kUntagged;
 
       // If we are writing into the typed data scale the index to
       // get byte offset. Otherwise ignore the scale.
-      if (!is_typed_data) {
+      if (!is_typed_access) {
         scale = 1;
       }
 
@@ -490,9 +501,11 @@
       if ((0 <= index_value) && (index_value < (kMaxInt32 / scale))) {
         const intptr_t scaled_index = index_value * scale;
 
-        // Guard against unaligned byte offsets.
-        if (!is_typed_data ||
-            Utils::IsAligned(scaled_index, ElementSizeMultiplier(size))) {
+        // Guard against unaligned byte offsets and access through raw
+        // memory pointer (which can be pointing into another typed data).
+        if (!is_typed_access ||
+            (!can_be_view &&
+             Utils::IsAligned(scaled_index, ElementSizeMultiplier(size)))) {
           set_kind(kConstantIndexed);
           set_element_size(size);
           index_constant_ = scaled_index;
diff --git a/runtime/vm/compiler/backend/slot.cc b/runtime/vm/compiler/backend/slot.cc
index 4a26aa7..8b14388 100644
--- a/runtime/vm/compiler/backend/slot.cc
+++ b/runtime/vm/compiler/backend/slot.cc
@@ -171,6 +171,15 @@
       &variable.name(), /*static_type=*/nullptr));
 }
 
+const Slot& Slot::GetTypeArgumentsIndexSlot(Thread* thread, intptr_t index) {
+  const intptr_t offset =
+      compiler::target::TypeArguments::type_at_offset(index);
+  const Slot& slot =
+      Slot(Kind::kTypeArgumentsIndex, IsImmutableBit::encode(true), kDynamicCid,
+           offset, ":argument", /*static_type=*/nullptr);
+  return SlotCache::Instance(thread).Canonicalize(slot);
+}
+
 const Slot& Slot::Get(const Field& field,
                       const ParsedFunction* parsed_function) {
   Thread* thread = Thread::Current();
@@ -263,6 +272,7 @@
 
   switch (kind_) {
     case Kind::kTypeArguments:
+    case Kind::kTypeArgumentsIndex:
       return (offset_in_bytes_ == other->offset_in_bytes_);
 
     case Kind::kCapturedVariable:
diff --git a/runtime/vm/compiler/backend/slot.h b/runtime/vm/compiler/backend/slot.h
index da23fbd..824b73a 100644
--- a/runtime/vm/compiler/backend/slot.h
+++ b/runtime/vm/compiler/backend/slot.h
@@ -71,7 +71,8 @@
   V(ArgumentsDescriptor, type_args_len, Smi, FINAL)                            \
   V(ArgumentsDescriptor, positional_count, Smi, FINAL)                         \
   V(ArgumentsDescriptor, count, Smi, FINAL)                                    \
-  V(Pointer, c_memory_address, Integer, FINAL)
+  V(Pointer, c_memory_address, Dynamic, FINAL)                                 \
+  V(Type, arguments, TypeArguments, FINAL)
 
 // Slot is an abstraction that describes an readable (and possibly writeable)
 // location within an object.
@@ -93,6 +94,9 @@
     // A slot used to store type arguments.
     kTypeArguments,
 
+    // A slot at a specific [index] in a [RawTypeArgument] vector.
+    kTypeArgumentsIndex,
+
     // A slot within a Context object that contains a value of a captured
     // local variable.
     kCapturedVariable,
@@ -118,6 +122,9 @@
   static const Slot& GetTypeArgumentsSlotAt(Thread* thread, intptr_t offset);
   static const Slot& GetTypeArgumentsSlotFor(Thread* thread, const Class& cls);
 
+  // Returns a slot at a specific [index] in a [RawTypeArgument] vector.
+  static const Slot& GetTypeArgumentsIndexSlot(Thread* thread, intptr_t index);
+
   // Returns a slot that represents the given captured local variable.
   static const Slot& GetContextVariableSlotFor(Thread* thread,
                                                const LocalVariable& var);
@@ -139,6 +146,7 @@
   bool IsDartField() const { return kind() == Kind::kDartField; }
   bool IsLocalVariable() const { return kind() == Kind::kCapturedVariable; }
   bool IsTypeArguments() const { return kind() == Kind::kTypeArguments; }
+  bool IsArgumentOfType() const { return kind() == Kind::kTypeArgumentsIndex; }
 
   const char* Name() const;
 
diff --git a/runtime/vm/compiler/ffi.cc b/runtime/vm/compiler/ffi.cc
index 3b3ce8c..596d43c 100644
--- a/runtime/vm/compiler/ffi.cc
+++ b/runtime/vm/compiler/ffi.cc
@@ -8,6 +8,7 @@
 
 #include "platform/globals.h"
 #include "vm/compiler/backend/locations.h"
+#include "vm/compiler/method_recognizer.h"
 #include "vm/compiler/runtime_api.h"
 #include "vm/compiler/stub_code_compiler.h"
 #include "vm/growable_array.h"
@@ -53,6 +54,56 @@
   return element_size_table[index];
 }
 
+classid_t ElementTypedDataCid(classid_t class_id) {
+  ASSERT(class_id >= kFfiPointerCid);
+  ASSERT(class_id < kFfiVoidCid);
+  ASSERT(class_id != kFfiNativeFunctionCid);
+  switch (class_id) {
+    case kFfiInt8Cid:
+      return kTypedDataInt8ArrayCid;
+    case kFfiUint8Cid:
+      return kTypedDataUint8ArrayCid;
+    case kFfiInt16Cid:
+      return kTypedDataInt16ArrayCid;
+    case kFfiUint16Cid:
+      return kTypedDataUint16ArrayCid;
+    case kFfiInt32Cid:
+      return kTypedDataInt32ArrayCid;
+    case kFfiUint32Cid:
+      return kTypedDataUint32ArrayCid;
+    case kFfiInt64Cid:
+      return kTypedDataInt64ArrayCid;
+    case kFfiUint64Cid:
+      return kTypedDataUint64ArrayCid;
+    case kFfiIntPtrCid:
+      return target::kWordSize == 4 ? kTypedDataInt32ArrayCid
+                                    : kTypedDataInt64ArrayCid;
+    case kFfiPointerCid:
+      return target::kWordSize == 4 ? kTypedDataUint32ArrayCid
+                                    : kTypedDataUint64ArrayCid;
+    case kFfiFloatCid:
+      return kTypedDataFloat32ArrayCid;
+    case kFfiDoubleCid:
+      return kTypedDataFloat64ArrayCid;
+    default:
+      UNREACHABLE();
+  }
+}
+
+classid_t RecognizedMethodTypeArgCid(MethodRecognizer::Kind kind) {
+  switch (kind) {
+#define LOAD_STORE(type)                                                       \
+  case MethodRecognizer::kFfiLoad##type:                                       \
+  case MethodRecognizer::kFfiStore##type:                                      \
+    return kFfi##type##Cid;
+    CLASS_LIST_FFI_NUMERIC(LOAD_STORE)
+    LOAD_STORE(Pointer)
+#undef LOAD_STORE
+    default:
+      UNREACHABLE();
+  }
+}
+
 // See pkg/vm/lib/transformations/ffi.dart, which makes these assumptions.
 struct AbiAlignmentDouble {
   int8_t use_one_byte;
@@ -124,8 +175,8 @@
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
 
-Representation TypeRepresentation(const AbstractType& result_type) {
-  switch (result_type.type_class_id()) {
+Representation TypeRepresentation(classid_t class_id) {
+  switch (class_id) {
     case kFfiFloatCid:
       return kUnboxedFloat;
     case kFfiDoubleCid:
@@ -142,6 +193,7 @@
     case kFfiUint64Cid:
       return kUnboxedInt64;
     case kFfiIntPtrCid:
+      return kUnboxedIntPtr;
     case kFfiPointerCid:
     case kFfiVoidCid:
       return kUnboxedFfiIntPtr;
@@ -183,7 +235,7 @@
   for (intptr_t i = 0; i < num_arguments; i++) {
     AbstractType& arg_type =
         AbstractType::Handle(signature.ParameterTypeAt(i + 1));
-    Representation rep = TypeRepresentation(arg_type);
+    Representation rep = TypeRepresentation(arg_type.type_class_id());
     // In non simulator mode host::CallingConventions == CallingConventions.
     // In simulator mode convert arguments to host representation.
     if (rep == kUnboxedFloat && CallingConventions::kAbiSoftFP) {
@@ -199,7 +251,7 @@
 template <class CallingConventions>
 Representation ResultRepresentationBase(const Function& signature) {
   AbstractType& arg_type = AbstractType::Handle(signature.result_type());
-  Representation rep = TypeRepresentation(arg_type);
+  Representation rep = TypeRepresentation(arg_type.type_class_id());
   if (rep == kUnboxedFloat && CallingConventions::kAbiSoftFP) {
     rep = kUnboxedInt32;
   } else if (rep == kUnboxedDouble && CallingConventions::kAbiSoftFP) {
diff --git a/runtime/vm/compiler/ffi.h b/runtime/vm/compiler/ffi.h
index 7922a80..ea35203 100644
--- a/runtime/vm/compiler/ffi.h
+++ b/runtime/vm/compiler/ffi.h
@@ -25,6 +25,12 @@
 // Storage size for an FFI type (extends 'ffi.NativeType').
 size_t ElementSizeInBytes(intptr_t class_id);
 
+// TypedData class id for a NativeType type, except for Void and NativeFunction.
+classid_t ElementTypedDataCid(classid_t class_id);
+
+// Returns the kFFi<type>Cid for the recognized load/store method [kind].
+classid_t RecognizedMethodTypeArgCid(MethodRecognizer::Kind kind);
+
 // These ABIs should be kept in sync with pkg/vm/lib/transformations/ffi.dart.
 enum class Abi {
   kWordSize64 = 0,
@@ -36,7 +42,7 @@
 Abi TargetAbi();
 
 // Unboxed representation of an FFI type (extends 'ffi.NativeType').
-Representation TypeRepresentation(const AbstractType& result_type);
+Representation TypeRepresentation(classid_t class_id);
 
 // Unboxed representation of an FFI type (extends 'ffi.NativeType') for 8 and 16
 // bit integers.
diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
index fad3c15..bb70abe 100644
--- a/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.cc
@@ -339,6 +339,20 @@
   return Fragment(instr);
 }
 
+Fragment BaseFlowGraphBuilder::LoadIndexedTypedData(classid_t class_id) {
+  // We use C behavior when dereferencing pointers, we assume alignment.
+  const AlignmentType alignment = kAlignedAccess;
+  const intptr_t scale = compiler::target::Instance::ElementSizeFor(class_id);
+
+  Value* index = Pop();
+  Value* c_pointer = Pop();
+  LoadIndexedInstr* instr =
+      new (Z) LoadIndexedInstr(c_pointer, index, scale, class_id, alignment,
+                               DeoptId::kNone, TokenPosition::kNoSource);
+  Push(instr);
+  return Fragment(instr);
+}
+
 Fragment BaseFlowGraphBuilder::LoadUntagged(intptr_t offset) {
   Value* object = Pop();
   auto load = new (Z) LoadUntaggedInstr(object, offset);
@@ -395,6 +409,21 @@
   return Fragment(untagged);
 }
 
+Fragment BaseFlowGraphBuilder::FloatToDouble() {
+  Value* value = Pop();
+  FloatToDoubleInstr* instr = new FloatToDoubleInstr(value, DeoptId::kNone);
+  Push(instr);
+  return Fragment(instr);
+}
+
+Fragment BaseFlowGraphBuilder::DoubleToFloat() {
+  Value* value = Pop();
+  DoubleToFloatInstr* instr = new DoubleToFloatInstr(
+      value, DeoptId::kNone, Instruction::SpeculativeMode::kNotSpeculative);
+  Push(instr);
+  return Fragment(instr);
+}
+
 Fragment BaseFlowGraphBuilder::LoadField(const Field& field) {
   return LoadNativeField(Slot::Get(MayCloneField(field), parsed_function_));
 }
@@ -533,7 +562,7 @@
       new (Z) StoreStaticFieldInstr(MayCloneField(field), Pop(), position));
 }
 
-Fragment BaseFlowGraphBuilder::StoreIndexed(intptr_t class_id) {
+Fragment BaseFlowGraphBuilder::StoreIndexed(classid_t class_id) {
   Value* value = Pop();
   Value* index = Pop();
   const StoreBarrierType emit_store_barrier =
@@ -546,6 +575,21 @@
   return Fragment(store);
 }
 
+Fragment BaseFlowGraphBuilder::StoreIndexedTypedData(classid_t class_id) {
+  // We use C behavior when dereferencing pointers, we assume alignment.
+  const AlignmentType alignment = kAlignedAccess;
+  const intptr_t scale = compiler::target::Instance::ElementSizeFor(class_id);
+
+  Value* value = Pop();
+  Value* index = Pop();
+  Value* c_pointer = Pop();
+  StoreIndexedInstr* instr = new (Z) StoreIndexedInstr(
+      c_pointer, index, value, kNoStoreBarrier, scale, class_id, alignment,
+      DeoptId::kNone, TokenPosition::kNoSource,
+      Instruction::SpeculativeMode::kNotSpeculative);
+  return Fragment(instr);
+}
+
 Fragment BaseFlowGraphBuilder::StoreLocal(TokenPosition position,
                                           LocalVariable* variable) {
   if (variable->is_captured()) {
@@ -718,6 +762,34 @@
   return Fragment(instr);
 }
 
+Fragment BaseFlowGraphBuilder::BinaryIntegerOp(Token::Kind kind,
+                                               Representation representation,
+                                               bool is_truncating) {
+  ASSERT(representation == kUnboxedInt32 || representation == kUnboxedUint32 ||
+         representation == kUnboxedInt64);
+  Value* right = Pop();
+  Value* left = Pop();
+  BinaryIntegerOpInstr* instr;
+  switch (representation) {
+    case kUnboxedInt32:
+      instr = new (Z) BinaryInt32OpInstr(kind, left, right, GetNextDeoptId());
+      break;
+    case kUnboxedUint32:
+      instr = new (Z) BinaryUint32OpInstr(kind, left, right, GetNextDeoptId());
+      break;
+    case kUnboxedInt64:
+      instr = new (Z) BinaryInt64OpInstr(kind, left, right, GetNextDeoptId());
+      break;
+    default:
+      UNREACHABLE();
+  }
+  if (is_truncating) {
+    instr->mark_truncating();
+  }
+  Push(instr);
+  return Fragment(instr);
+}
+
 Fragment BaseFlowGraphBuilder::LoadFpRelativeSlot(intptr_t offset,
                                                   CompileType result_type) {
   LoadIndexedUnsafeInstr* instr =
@@ -892,6 +964,7 @@
   CheckNullInstr* check_null =
       new (Z) CheckNullInstr(Pop(), function_name, GetNextDeoptId(), position);
 
+  // Does not use the redefinition, no `Push(check_null)`.
   instructions <<= check_null;
 
   if (clear_the_temp) {
@@ -905,6 +978,15 @@
   return instructions;
 }
 
+Fragment BaseFlowGraphBuilder::CheckNullOptimized(TokenPosition position,
+                                                  const String& function_name) {
+  Value* value = Pop();
+  CheckNullInstr* check_null =
+      new (Z) CheckNullInstr(value, function_name, GetNextDeoptId(), position);
+  Push(check_null);  // Use the redefinition.
+  return Fragment(check_null);
+}
+
 void BaseFlowGraphBuilder::RecordUncheckedEntryPoint(
     GraphEntryInstr* graph_entry,
     FunctionEntryInstr* unchecked_entry) {
@@ -1009,6 +1091,27 @@
   }
 }
 
+Fragment BaseFlowGraphBuilder::AssertAssignable(
+    TokenPosition position,
+    const AbstractType& dst_type,
+    const String& dst_name,
+    AssertAssignableInstr::Kind kind) {
+  if (!I->should_emit_strong_mode_checks()) {
+    return Drop() + Drop();
+  }
+
+  Value* function_type_args = Pop();
+  Value* instantiator_type_args = Pop();
+  Value* value = Pop();
+
+  AssertAssignableInstr* instr = new (Z) AssertAssignableInstr(
+      position, value, instantiator_type_args, function_type_args, dst_type,
+      dst_name, GetNextDeoptId(), kind);
+  Push(instr);
+
+  return Fragment(instr);
+}
+
 }  // namespace kernel
 }  // namespace dart
 
diff --git a/runtime/vm/compiler/frontend/base_flow_graph_builder.h b/runtime/vm/compiler/frontend/base_flow_graph_builder.h
index dbd2b68..8caed54 100644
--- a/runtime/vm/compiler/frontend/base_flow_graph_builder.h
+++ b/runtime/vm/compiler/frontend/base_flow_graph_builder.h
@@ -161,12 +161,16 @@
   Fragment LoadField(const Field& field);
   Fragment LoadNativeField(const Slot& native_field);
   Fragment LoadIndexed(intptr_t index_scale);
+  // Takes a [class_id] valid for StoreIndexed.
+  Fragment LoadIndexedTypedData(classid_t class_id);
 
   Fragment LoadUntagged(intptr_t offset);
   Fragment StoreUntagged(intptr_t offset);
   Fragment ConvertUntaggedToIntptr();
   Fragment ConvertIntptrToUntagged();
   Fragment UnboxSmiToIntptr();
+  Fragment FloatToDouble();
+  Fragment DoubleToFloat();
 
   Fragment AddIntptrIntegers();
 
@@ -192,7 +196,9 @@
   Fragment LoadStaticField();
   Fragment RedefinitionWithType(const AbstractType& type);
   Fragment StoreStaticField(TokenPosition position, const Field& field);
-  Fragment StoreIndexed(intptr_t class_id);
+  Fragment StoreIndexed(classid_t class_id);
+  // Takes a [class_id] valid for StoreIndexed.
+  Fragment StoreIndexedTypedData(classid_t class_id);
 
   void Push(Definition* definition);
   Definition* Peek(intptr_t depth = 0);
@@ -241,6 +247,9 @@
   Fragment NullConstant();
   Fragment SmiRelationalOp(Token::Kind kind);
   Fragment SmiBinaryOp(Token::Kind op, bool is_truncating = false);
+  Fragment BinaryIntegerOp(Token::Kind op,
+                           Representation representation,
+                           bool is_truncating = false);
   Fragment LoadFpRelativeSlot(intptr_t offset, CompileType result_type);
   Fragment StoreFpRelativeSlot(intptr_t offset);
   Fragment BranchIfTrue(TargetEntryInstr** then_entry,
@@ -333,11 +342,23 @@
   // 'function_name' is a selector which is being called (reported in
   // NoSuchMethod message).
   // Sets 'receiver' to 'null' after the check if 'clear_the_temp'.
+  // Note that this does _not_ use the result of the CheckNullInstr, so it does
+  // not create a data depedency and might break with code motion.
   Fragment CheckNull(TokenPosition position,
                      LocalVariable* receiver,
                      const String& function_name,
                      bool clear_the_temp = true);
 
+  // Pops the top of the stack, checks it for null, and pushes the result on
+  // the stack to create a data dependency.
+  // 'function_name' is a selector which is being called (reported in
+  // NoSuchMethod message).
+  // Note that the result can currently only be used in optimized code, because
+  // optimized code uses FlowGraph::RemoveRedefinitions to remove the
+  // redefinitions, while unoptimized code does not.
+  Fragment CheckNullOptimized(TokenPosition position,
+                              const String& function_name);
+
   // Records extra unchecked entry point 'unchecked_entry' in 'graph_entry'.
   void RecordUncheckedEntryPoint(GraphEntryInstr* graph_entry,
                                  FunctionEntryInstr* unchecked_entry);
@@ -361,6 +382,14 @@
   // _StringBase._interpolate call.
   Fragment StringInterpolate(TokenPosition position);
 
+  // Pops function type arguments, instantiator type arguments and value; and
+  // type checks value against the type arguments.
+  Fragment AssertAssignable(
+      TokenPosition position,
+      const AbstractType& dst_type,
+      const String& dst_name,
+      AssertAssignableInstr::Kind kind = AssertAssignableInstr::kUnknown);
+
   // Returns true if we're currently recording deopt_id -> context level
   // mapping.
   bool is_recording_context_levels() const {
diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
index 6edaba1..39adce9 100644
--- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
@@ -180,17 +180,17 @@
     }
 
     local_vars_.EnsureLength(num_bytecode_locals, nullptr);
-    for (intptr_t i = num_param_locals; i < num_bytecode_locals; ++i) {
-      String& name =
-          String::ZoneHandle(Z, Symbols::NewFormatted(thread(), "var%" Pd, i));
+    intptr_t idx = num_param_locals;
+    for (; idx < num_bytecode_locals; ++idx) {
+      String& name = String::ZoneHandle(
+          Z, Symbols::NewFormatted(thread(), "var%" Pd, idx));
       LocalVariable* local = new (Z)
           LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
                         name, Object::dynamic_type());
-      local->set_index(VariableIndex(-i));
-      local_vars_[i] = local;
+      local->set_index(VariableIndex(-idx));
+      local_vars_[idx] = local;
     }
 
-    intptr_t idx = num_bytecode_locals;
     if (exception_var_ != nullptr) {
       exception_var_->set_index(VariableIndex(-idx));
       ++idx;
@@ -845,41 +845,48 @@
   const intptr_t argc = DecodeOperandF().value();
 
   const auto recognized_kind = MethodRecognizer::RecognizeKind(target);
-  if (recognized_kind == MethodRecognizer::kFfiAsFunctionInternal) {
-    BuildFfiAsFunction();
-    return;
-  } else if (FLAG_precompiled_mode &&
-             recognized_kind == MethodRecognizer::kFfiNativeCallbackFunction) {
-    BuildFfiNativeCallbackFunction();
-    return;
-  }
-
-  // Recognize identical() call.
-  // Note: similar optimization is performed in AST flow graph builder - see
-  // StreamingFlowGraphBuilder::BuildStaticInvocation, special_case_identical.
-  // TODO(alexmarkov): find a better place for this optimization.
-  if (target.name() == Symbols::Identical().raw()) {
-    const auto& owner = Class::Handle(Z, target.Owner());
-    if (owner.IsTopLevel() && (owner.library() == Library::CoreLibrary())) {
+  switch (recognized_kind) {
+    case MethodRecognizer::kFfiAsFunctionInternal:
+      BuildFfiAsFunction();
+      return;
+    case MethodRecognizer::kFfiNativeCallbackFunction:
+      if (FLAG_precompiled_mode) {
+        BuildFfiNativeCallbackFunction();
+        return;
+      }
+      break;
+    case MethodRecognizer::kObjectIdentical:
+      // Note: similar optimization is performed in AST flow graph builder -
+      // see StreamingFlowGraphBuilder::BuildStaticInvocation,
+      // special_case_identical.
+      // TODO(alexmarkov): find a better place for this optimization.
       ASSERT(argc == 2);
       code_ += B->StrictCompare(Token::kEQ_STRICT, /*number_check=*/true);
       return;
-    }
-  }
-
-  if (!FLAG_causal_async_stacks &&
-      recognized_kind == MethodRecognizer::kAsyncStackTraceHelper) {
-    ASSERT(argc == 1);
-    // Drop the ignored parameter to _asyncStackTraceHelper(:async_op).
-    code_ += B->Drop();
-    code_ += B->NullConstant();
-    return;
-  }
-
-  if (recognized_kind == MethodRecognizer::kStringBaseInterpolate) {
-    ASSERT(argc == 1);
-    code_ += B->StringInterpolate(position_);
-    return;
+    case MethodRecognizer::kAsyncStackTraceHelper:
+    case MethodRecognizer::kSetAsyncThreadStackTrace:
+      if (!FLAG_causal_async_stacks) {
+        ASSERT(argc == 1);
+        // Drop the ignored parameter to _asyncStackTraceHelper(:async_op) or
+        // _setAsyncThreadStackTrace(stackTrace).
+        code_ += B->Drop();
+        code_ += B->NullConstant();
+        return;
+      }
+      break;
+    case MethodRecognizer::kClearAsyncThreadStackTrace:
+      if (!FLAG_causal_async_stacks) {
+        ASSERT(argc == 0);
+        code_ += B->NullConstant();
+        return;
+      }
+      break;
+    case MethodRecognizer::kStringBaseInterpolate:
+      ASSERT(argc == 1);
+      code_ += B->StringInterpolate(position_);
+      return;
+    default:
+      break;
   }
 
   const Array& arg_desc_array =
@@ -1289,7 +1296,8 @@
 
   LoadStackSlots(1);
   const intptr_t offset =
-      Smi::Cast(ConstantAt(DecodeOperandD()).value()).Value() * kWordSize;
+      Smi::Cast(ConstantAt(DecodeOperandD()).value()).Value() *
+      compiler::target::kWordSize;
 
   code_ += B->LoadNativeField(Slot::GetTypeArgumentsSlotAt(thread(), offset));
 }
@@ -2143,8 +2151,9 @@
   object_pool_ = bytecode.object_pool();
   bytecode_instr_ = reinterpret_cast<const KBCInstr*>(bytecode.PayloadStart());
 
+  scratch_var_ = parsed_function_->EnsureExpressionTemp();
+
   if (KernelBytecode::IsEntryOptionalOpcode(bytecode_instr_)) {
-    scratch_var_ = parsed_function_->EnsureExpressionTemp();
     AllocateParametersAndLocalsForEntryOptional();
   } else if (KernelBytecode::IsEntryOpcode(bytecode_instr_)) {
     AllocateLocalVariables(DecodeOperandD());
@@ -2155,6 +2164,46 @@
   } else {
     UNREACHABLE();
   }
+
+  if (function().IsGeneric()) {
+    // For recognized methods we generate the IL by hand. Yet we need to find
+    // out which [LocalVariable] is holding the function type arguments. We
+    // scan the bytecode for the CheckFunctionTypeArgs bytecode.
+    //
+    // Note that we cannot add an extra local variable for the type argument
+    // in [AllocateLocalVariables]. We sometimes reuse the same ParsedFunction
+    // multiple times. For non-recognized generic bytecode functions
+    // ParsedFunction::RawTypeArgumentsVariable() is set during flow graph
+    // construction (after local variables are allocated). So the next time,
+    // if ParsedFunction is reused, we would allocate an extra local variable.
+    // TODO(alexmarkov): revise how function type args variable is allocated
+    // and avoid looking at CheckFunctionTypeArgs bytecode.
+    const KBCInstr* instr =
+        reinterpret_cast<const KBCInstr*>(bytecode.PayloadStart());
+    const KBCInstr* end = reinterpret_cast<const KBCInstr*>(
+        bytecode.PayloadStart() + bytecode.Size());
+
+    LocalVariable* type_args_var = nullptr;
+    while (instr < end) {
+      if (KernelBytecode::IsCheckFunctionTypeArgs(instr)) {
+        const intptr_t expected_num_type_args = KernelBytecode::DecodeA(instr);
+        if (expected_num_type_args > 0) {  // Exclude weird closure case.
+          type_args_var = LocalVariableAt(KernelBytecode::DecodeE(instr));
+          break;
+        }
+      }
+      instr = KernelBytecode::Next(instr);
+    }
+
+    // Every generic function *must* have a kCheckFunctionTypeArgs bytecode.
+    ASSERT(type_args_var != nullptr);
+
+    // Normally the flow graph building code of bytecode will, as a side-effect
+    // of building the flow graph, register the function type arguments variable
+    // in the [ParsedFunction] (see [BuildCheckFunctionTypeArgs]).
+    parsed_function_->set_function_type_arguments(type_args_var);
+    parsed_function_->SetRawTypeArgumentsVariable(type_args_var);
+  }
 }
 
 intptr_t BytecodeFlowGraphBuilder::UpdateScope(
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.cc b/runtime/vm/compiler/frontend/bytecode_reader.cc
index b72cb90..5399205 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.cc
+++ b/runtime/vm/compiler/frontend/bytecode_reader.cc
@@ -8,6 +8,7 @@
 #include "vm/bootstrap.h"
 #include "vm/class_finalizer.h"
 #include "vm/code_descriptors.h"
+#include "vm/compiler/aot/precompiler.h"  // For Obfuscator
 #include "vm/compiler/assembler/disassembler_kbc.h"
 #include "vm/compiler/frontend/bytecode_scope_builder.h"
 #include "vm/constants_kbc.h"
@@ -1195,6 +1196,15 @@
   reader_.ReadUInt32();  // Skip annotations.numItems
   const intptr_t annotations_offset = start_offset + reader_.ReadUInt32();
 
+  intptr_t num_protected_names = 0;
+  intptr_t protected_names_offset = 0;
+  static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 23,
+                "Cleanup condition");
+  if (version >= 23) {
+    num_protected_names = reader_.ReadUInt32();
+    protected_names_offset = start_offset + reader_.ReadUInt32();
+  }
+
   // Read header of string table.
   reader_.set_offset(string_table_offset);
   const intptr_t num_one_byte_strings = reader_.ReadUInt32();
@@ -1231,6 +1241,21 @@
     bytecode_component.SetObject(i, offs);
   }
 
+  // Read protected names.
+  if (I->obfuscate() && (num_protected_names > 0)) {
+    bytecode_component_ = &bytecode_component;
+
+    reader_.set_offset(protected_names_offset);
+    Obfuscator obfuscator(thread_, Object::null_string());
+    auto& name = String::Handle(Z);
+    for (intptr_t i = 0; i < num_protected_names; ++i) {
+      name = ReadString();
+      obfuscator.PreventRenaming(name);
+    }
+
+    bytecode_component_ = nullptr;
+  }
+
   H.SetBytecodeComponent(bytecode_component_array);
 
   return bytecode_component_array.raw();
@@ -1326,6 +1351,10 @@
   // pkg/vm/lib/bytecode/object_table.dart.
   const int kFlagHasSourceFile = kFlagBit0;
 
+  // Name flags, must be in sync with _NameHandle constants in
+  // pkg/vm/lib/bytecode/object_table.dart.
+  const intptr_t kFlagIsPublic = kFlagBit0;
+
   const intptr_t kind = (header >> kKindShift) & kKindMask;
   const intptr_t flags = header & kFlagsMask;
 
@@ -1448,13 +1477,28 @@
       return closures_->At(closure_index);
     }
     case kName: {
-      const Library& library = Library::CheckedHandle(Z, ReadObject());
-      if (library.IsNull()) {
-        return ReadString();
+      if ((flags & kFlagIsPublic) == 0) {
+        const Library& library = Library::CheckedHandle(Z, ReadObject());
+        static_assert(KernelBytecode::kMinSupportedBytecodeFormatVersion < 23,
+                      "Cleanup library.IsNull() condition");
+        if (!library.IsNull()) {
+          auto& name =
+              String::Handle(Z, ReadString(/* is_canonical = */ false));
+          name = library.PrivateName(name);
+          if (I->obfuscate()) {
+            const auto& library_key = String::Handle(Z, library.private_key());
+            Obfuscator obfuscator(thread_, library_key);
+            return obfuscator.Rename(name);
+          }
+          return name.raw();
+        }
+      }
+      if (I->obfuscate()) {
+        Obfuscator obfuscator(thread_, Object::null_string());
+        const auto& name = String::Handle(Z, ReadString());
+        return obfuscator.Rename(name);
       } else {
-        const String& name =
-            String::Handle(Z, ReadString(/* is_canonical = */ false));
-        return library.PrivateName(name);
+        return ReadString();
       }
     }
     case kTypeArguments: {
@@ -1519,6 +1563,7 @@
     kBool,
     kSymbol,
     kTearOffInstantiation,
+    kString,
   };
 
   switch (tag) {
@@ -1610,6 +1655,8 @@
           Context::Handle(Z, closure.context()), Heap::kOld);
       return H.Canonicalize(closure);
     }
+    case kString:
+      return ReadString();
     default:
       UNREACHABLE();
   }
@@ -2531,6 +2578,7 @@
   const int kUsesDartMirrorsFlag = 1 << 0;
   const int kUsesDartFfiFlag = 1 << 1;
   const int kHasExtensionsFlag = 1 << 2;
+  const int kIsNonNullableByDefaultFlag = 1 << 3;
 
   ASSERT(library.is_declared_in_bytecode());
   ASSERT(!library.Loaded());
@@ -2575,6 +2623,10 @@
     H.AddPotentialExtensionLibrary(library);
   }
 
+  if ((flags & kIsNonNullableByDefaultFlag) != 0) {
+    library.set_is_nnbd(true);
+  }
+
   // The bootstrapper will take care of creating the native wrapper classes,
   // but we will add the synthetic constructors to them here.
   if (name.raw() ==
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.h b/runtime/vm/compiler/frontend/bytecode_reader.h
index 418d021..f3d2b12 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.h
+++ b/runtime/vm/compiler/frontend/bytecode_reader.h
@@ -235,7 +235,7 @@
   ActiveClass* const active_class_;
   Thread* const thread_;
   Zone* const zone_;
-  BytecodeComponentData* const bytecode_component_;
+  BytecodeComponentData* bytecode_component_;
   Array* closures_ = nullptr;
   const TypeArguments* function_type_type_parameters_ = nullptr;
   GrowableObjectArray* pending_recursive_types_ = nullptr;
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 80df237..579d7bf 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -162,10 +162,9 @@
 }
 
 Fragment StreamingFlowGraphBuilder::BuildFieldInitializer(
-    NameIndex canonical_name) {
+    const Field& field,
+    bool only_for_side_effects) {
   ASSERT(Error::Handle(Z, H.thread()->sticky_error()).IsNull());
-  Field& field =
-      Field::ZoneHandle(Z, H.LookupFieldByKernelField(canonical_name));
   if (PeekTag() == kNullLiteral) {
     SkipExpression();  // read past the null literal.
     if (H.thread()->IsMutatorThread()) {
@@ -177,13 +176,19 @@
   }
 
   Fragment instructions;
-  instructions += LoadLocal(parsed_function()->receiver_var());
+  if (!only_for_side_effects) {
+    instructions += LoadLocal(parsed_function()->receiver_var());
+  }
   // All closures created inside BuildExpression will have
   // field.RawOwner() as its owner.
   closure_owner_ = field.RawOwner();
   instructions += BuildExpression();
   closure_owner_ = Object::null();
-  instructions += flow_graph_builder_->StoreInstanceFieldGuarded(field, true);
+  if (only_for_side_effects) {
+    instructions += Drop();
+  } else {
+    instructions += flow_graph_builder_->StoreInstanceFieldGuarded(field, true);
+  }
   return instructions;
 }
 
@@ -200,47 +205,105 @@
     initializers_offset = ReaderOffset();
   }
 
-  // These come from:
-  //   class A {
-  //     var x = (expr);
-  //   }
-  // We don't want to do that when this is a Redirecting Constructors though
-  // (i.e. has a single initializer being of type kRedirectingInitializer).
   bool is_redirecting_constructor = false;
+
+  // Field which will be initialized by the initializer with the given index.
+  GrowableArray<const Field*> initializer_fields(5);
+
+  // Check if this is a redirecting constructor and collect all fields which
+  // will be initialized by the constructor initializer list.
   {
     AlternativeReadingScope alt(&reader_, initializers_offset);
-    intptr_t list_length = ReadListLength();  // read initializers list length.
-    bool no_field_initializers = true;
+
+    const intptr_t list_length =
+        ReadListLength();  // read initializers list length.
+    initializer_fields.EnsureLength(list_length, nullptr);
+
+    bool has_field_initializers = false;
     for (intptr_t i = 0; i < list_length; ++i) {
       if (PeekTag() == kRedirectingInitializer) {
         is_redirecting_constructor = true;
       } else if (PeekTag() == kFieldInitializer) {
-        no_field_initializers = false;
+        has_field_initializers = true;
+        ReadTag();
+        ReadBool();
+        const NameIndex field_name = ReadCanonicalNameReference();
+        const Field& field =
+            Field::Handle(Z, H.LookupFieldByKernelField(field_name));
+        initializer_fields[i] = &field;
+        SkipExpression();
+        continue;
       }
       SkipInitializer();
     }
-    ASSERT(is_redirecting_constructor ? no_field_initializers : true);
+    ASSERT(!is_redirecting_constructor || !has_field_initializers);
   }
 
+  // These come from:
+  //
+  //   class A {
+  //     var x = (expr);
+  //   }
+  //
+  // We don't want to do that when this is a Redirecting Constructors though
+  // (i.e. has a single initializer being of type kRedirectingInitializer).
   if (!is_redirecting_constructor) {
+    // Sort list of fields (represented as their kernel offsets) which will
+    // be initialized by the constructor initializer list. We will not emit
+    // StoreInstanceField instructions for those initializers though we will
+    // still evaluate initialization expression for its side effects.
+    GrowableArray<intptr_t> constructor_initialized_field_offsets(
+        initializer_fields.length());
+    for (auto field : initializer_fields) {
+      if (field != nullptr) {
+        constructor_initialized_field_offsets.Add(field->kernel_offset());
+      }
+    }
+
+    constructor_initialized_field_offsets.Sort(
+        [](const intptr_t* a, const intptr_t* b) {
+          return static_cast<int>(*a) - static_cast<int>(*b);
+        });
+    constructor_initialized_field_offsets.Add(-1);
+
+    ExternalTypedData& kernel_data = ExternalTypedData::Handle(Z);
     Array& class_fields = Array::Handle(Z, parent_class.fields());
     Field& class_field = Field::Handle(Z);
+    intptr_t next_constructor_initialized_field_index = 0;
     for (intptr_t i = 0; i < class_fields.Length(); ++i) {
       class_field ^= class_fields.At(i);
       if (!class_field.is_static()) {
-        ExternalTypedData& kernel_data =
-            ExternalTypedData::Handle(Z, class_field.KernelData());
+        const intptr_t field_offset = class_field.kernel_offset();
+
+        // Check if this field will be initialized by the constructor
+        // initializer list.
+        // Note that both class_fields and the list of initialized fields
+        // are sorted by their kernel offset (by construction) -
+        // so we don't need to perform the search.
+        bool is_constructor_initialized = false;
+        const intptr_t constructor_initialized_field_offset =
+            constructor_initialized_field_offsets
+                [next_constructor_initialized_field_index];
+        if (constructor_initialized_field_offset == field_offset) {
+          next_constructor_initialized_field_index++;
+          is_constructor_initialized = true;
+        }
+
+        kernel_data = class_field.KernelData();
         ASSERT(!kernel_data.IsNull());
-        intptr_t field_offset = class_field.kernel_offset();
         AlternativeReadingScopeWithNewData alt(&reader_, &kernel_data,
                                                field_offset);
         FieldHelper field_helper(this);
         field_helper.ReadUntilExcluding(FieldHelper::kInitializer);
-        Tag initializer_tag = ReadTag();  // read first part of initializer.
+        const Tag initializer_tag = ReadTag();
         if (initializer_tag == kSomething) {
           EnterScope(field_offset);
+          // If this field is initialized in constructor then we can ignore the
+          // value produced by the field initializer. However we still need to
+          // execute it for its side effects.
           instructions += BuildFieldInitializer(
-              field_helper.canonical_name_);  // read initializer.
+              Field::ZoneHandle(Z, class_field.raw()),
+              /*only_for_side_effects=*/is_constructor_initialized);
           ExitScope(field_offset);
         }
       }
@@ -264,9 +327,10 @@
           UNIMPLEMENTED();
           return Fragment();
         case kFieldInitializer: {
-          NameIndex canonical_name =
-              ReadCanonicalNameReference();  // read field_reference.
-          instructions += BuildFieldInitializer(canonical_name);  // read value.
+          ReadCanonicalNameReference();
+          instructions += BuildFieldInitializer(
+              Field::ZoneHandle(Z, initializer_fields[i]->raw()),
+              /*only_for_size_effects=*/false);
           break;
         }
         case kAssertInitializer: {
@@ -3511,7 +3575,7 @@
     // or explicitly written by the user, in both cases we use an assert
     // assignable.
     instructions += LoadLocal(MakeTemporary());
-    instructions += B->AssertAssignable(
+    instructions += B->AssertAssignableLoadTypeArguments(
         position, type,
         is_type_error ? Symbols::Empty() : Symbols::InTypeCast(),
         AssertAssignableInstr::kInsertedByFrontend);
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
index e26f76d..830ec2a 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
@@ -67,7 +67,8 @@
   void ReadDefaultFunctionTypeArguments(const Function& function);
 
   FlowGraph* BuildGraphOfFieldInitializer();
-  Fragment BuildFieldInitializer(NameIndex canonical_name);
+  Fragment BuildFieldInitializer(const Field& field,
+                                 bool only_for_side_effects);
   Fragment BuildInitializers(const Class& parent_class);
   FlowGraph* BuildGraphOfFunction(bool constructor);
 
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.cc b/runtime/vm/compiler/frontend/kernel_to_il.cc
index 4748658..8bf4ef6 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.cc
+++ b/runtime/vm/compiler/frontend/kernel_to_il.cc
@@ -692,6 +692,32 @@
     case MethodRecognizer::kTypedData_Float32x4ArrayView_factory:
     case MethodRecognizer::kTypedData_Int32x4ArrayView_factory:
     case MethodRecognizer::kTypedData_Float64x2ArrayView_factory:
+    case MethodRecognizer::kFfiLoadInt8:
+    case MethodRecognizer::kFfiLoadInt16:
+    case MethodRecognizer::kFfiLoadInt32:
+    case MethodRecognizer::kFfiLoadInt64:
+    case MethodRecognizer::kFfiLoadUint8:
+    case MethodRecognizer::kFfiLoadUint16:
+    case MethodRecognizer::kFfiLoadUint32:
+    case MethodRecognizer::kFfiLoadUint64:
+    case MethodRecognizer::kFfiLoadIntPtr:
+    case MethodRecognizer::kFfiLoadFloat:
+    case MethodRecognizer::kFfiLoadDouble:
+    case MethodRecognizer::kFfiLoadPointer:
+    case MethodRecognizer::kFfiStoreInt8:
+    case MethodRecognizer::kFfiStoreInt16:
+    case MethodRecognizer::kFfiStoreInt32:
+    case MethodRecognizer::kFfiStoreInt64:
+    case MethodRecognizer::kFfiStoreUint8:
+    case MethodRecognizer::kFfiStoreUint16:
+    case MethodRecognizer::kFfiStoreUint32:
+    case MethodRecognizer::kFfiStoreUint64:
+    case MethodRecognizer::kFfiStoreIntPtr:
+    case MethodRecognizer::kFfiStoreFloat:
+    case MethodRecognizer::kFfiStoreDouble:
+    case MethodRecognizer::kFfiStorePointer:
+    case MethodRecognizer::kFfiFromAddress:
+    case MethodRecognizer::kFfiGetAddress:
 #endif  // !defined(TARGET_ARCH_DBC)
     // This list must be kept in sync with BytecodeReaderHelper::NativeEntry in
     // runtime/vm/compiler/frontend/bytecode_reader.cc and implemented in the
@@ -1020,6 +1046,233 @@
       ASSERT(function.NumParameters() == 0);
       body += IntConstant(static_cast<int64_t>(compiler::ffi::TargetAbi()));
       break;
+    case MethodRecognizer::kFfiLoadInt8:
+    case MethodRecognizer::kFfiLoadInt16:
+    case MethodRecognizer::kFfiLoadInt32:
+    case MethodRecognizer::kFfiLoadInt64:
+    case MethodRecognizer::kFfiLoadUint8:
+    case MethodRecognizer::kFfiLoadUint16:
+    case MethodRecognizer::kFfiLoadUint32:
+    case MethodRecognizer::kFfiLoadUint64:
+    case MethodRecognizer::kFfiLoadIntPtr:
+    case MethodRecognizer::kFfiLoadFloat:
+    case MethodRecognizer::kFfiLoadDouble:
+    case MethodRecognizer::kFfiLoadPointer: {
+      const classid_t ffi_type_arg_cid =
+          compiler::ffi::RecognizedMethodTypeArgCid(kind);
+      const classid_t typed_data_cid =
+          compiler::ffi::ElementTypedDataCid(ffi_type_arg_cid);
+      const Representation representation =
+          compiler::ffi::TypeRepresentation(ffi_type_arg_cid);
+
+      // Check Dart signature type.
+      const auto& receiver_type =
+          AbstractType::Handle(function.ParameterTypeAt(0));
+      const auto& type_args = TypeArguments::Handle(receiver_type.arguments());
+      const auto& type_arg = AbstractType::Handle(type_args.TypeAt(0));
+      ASSERT(ffi_type_arg_cid == type_arg.type_class_id());
+
+      ASSERT(function.NumParameters() == 2);
+      body += LoadLocal(parsed_function_->RawParameterVariable(0));  // Pointer.
+      body += CheckNullOptimized(TokenPosition::kNoSource,
+                                 String::ZoneHandle(Z, function.name()));
+      body += LoadNativeField(Slot::Pointer_c_memory_address());
+      body += UnboxTruncate(kUnboxedFfiIntPtr);
+      // We do Pointer.address + index * sizeOf<T> manually because LoadIndexed
+      // does not support Mint index arguments.
+      body += LoadLocal(parsed_function_->RawParameterVariable(1));  // Index.
+      body += CheckNullOptimized(TokenPosition::kNoSource,
+                                 String::ZoneHandle(Z, function.name()));
+      body += UnboxTruncate(kUnboxedFfiIntPtr);
+      body += IntConstant(compiler::ffi::ElementSizeInBytes(ffi_type_arg_cid));
+      body += UnboxTruncate(kUnboxedIntPtr);
+      // TODO(38831): Implement Shift for Uint32, and use that instead.
+      body +=
+          BinaryIntegerOp(Token::kMUL, kUnboxedFfiIntPtr, /* truncate= */ true);
+      body +=
+          BinaryIntegerOp(Token::kADD, kUnboxedFfiIntPtr, /* truncate= */ true);
+      body += ConvertIntptrToUntagged();
+      body += IntConstant(0);
+      body += LoadIndexedTypedData(typed_data_cid);
+      if (kind == MethodRecognizer::kFfiLoadFloat ||
+          kind == MethodRecognizer::kFfiLoadDouble) {
+        if (kind == MethodRecognizer::kFfiLoadFloat) {
+          body += FloatToDouble();
+        }
+        body += Box(kUnboxedDouble);
+      } else {
+        body += Box(representation);
+        if (kind == MethodRecognizer::kFfiLoadPointer) {
+          const auto class_table = thread_->isolate()->class_table();
+          ASSERT(class_table->HasValidClassAt(kFfiPointerCid));
+          const auto& pointer_class =
+              Class::ZoneHandle(H.zone(), class_table->At(kFfiPointerCid));
+
+          // We find the reified type to use for the pointer allocation.
+          //
+          // Call sites to this recognized method are guaranteed to pass a
+          // Pointer<Pointer<X>> as RawParameterVariable(0). This function
+          // will return a Pointer<X> object - for which we inspect the
+          // reified type on the argument.
+          //
+          // The following is safe to do, as (1) we are guaranteed to have a
+          // Pointer<Pointer<X>> as argument, and (2) the bound on the pointer
+          // type parameter guarantees X is an interface type.
+          ASSERT(function.NumTypeParameters() == 1);
+          LocalVariable* address = MakeTemporary();
+          body += LoadLocal(parsed_function_->RawParameterVariable(0));
+          body += LoadNativeField(
+              Slot::GetTypeArgumentsSlotFor(thread_, pointer_class));
+          body += LoadNativeField(Slot::GetTypeArgumentsIndexSlot(
+              thread_, Pointer::kNativeTypeArgPos));
+          body += LoadNativeField(Slot::Type_arguments());
+          body += PushArgument();  // We instantiate a Pointer<X>.
+          body += AllocateObject(TokenPosition::kNoSource, pointer_class, 1);
+          LocalVariable* pointer = MakeTemporary();
+          body += LoadLocal(pointer);
+          body += LoadLocal(address);
+          body += StoreInstanceField(TokenPosition::kNoSource,
+                                     Slot::Pointer_c_memory_address());
+          body += DropTempsPreserveTop(1);  // Drop [address] keep [pointer].
+        }
+      }
+    } break;
+    case MethodRecognizer::kFfiStoreInt8:
+    case MethodRecognizer::kFfiStoreInt16:
+    case MethodRecognizer::kFfiStoreInt32:
+    case MethodRecognizer::kFfiStoreInt64:
+    case MethodRecognizer::kFfiStoreUint8:
+    case MethodRecognizer::kFfiStoreUint16:
+    case MethodRecognizer::kFfiStoreUint32:
+    case MethodRecognizer::kFfiStoreUint64:
+    case MethodRecognizer::kFfiStoreIntPtr:
+    case MethodRecognizer::kFfiStoreFloat:
+    case MethodRecognizer::kFfiStoreDouble:
+    case MethodRecognizer::kFfiStorePointer: {
+      const classid_t ffi_type_arg_cid =
+          compiler::ffi::RecognizedMethodTypeArgCid(kind);
+      const classid_t typed_data_cid =
+          compiler::ffi::ElementTypedDataCid(ffi_type_arg_cid);
+      const Representation representation =
+          compiler::ffi::TypeRepresentation(ffi_type_arg_cid);
+
+      // Check Dart signature type.
+      const auto& receiver_type =
+          AbstractType::Handle(function.ParameterTypeAt(0));
+      const auto& type_args = TypeArguments::Handle(receiver_type.arguments());
+      const auto& type_arg = AbstractType::Handle(type_args.TypeAt(0));
+      ASSERT(ffi_type_arg_cid == type_arg.type_class_id());
+
+      LocalVariable* arg_pointer = parsed_function_->RawParameterVariable(0);
+      LocalVariable* arg_index = parsed_function_->RawParameterVariable(1);
+      LocalVariable* arg_value = parsed_function_->RawParameterVariable(2);
+
+      if (kind == MethodRecognizer::kFfiStorePointer) {
+        // Do type check before anything untagged is on the stack.
+        const auto class_table = thread_->isolate()->class_table();
+        ASSERT(class_table->HasValidClassAt(kFfiPointerCid));
+        const auto& pointer_class =
+            Class::ZoneHandle(H.zone(), class_table->At(kFfiPointerCid));
+        const auto& pointer_type_args =
+            TypeArguments::Handle(pointer_class.type_parameters());
+        const auto& pointer_type_arg =
+            AbstractType::Handle(pointer_type_args.TypeAt(0));
+
+        // The method _storePointer is a top level generic function, not an
+        // instance method on a generic class.
+        ASSERT(!type_arg.IsInstantiated(kFunctions));
+        ASSERT(type_arg.IsInstantiated(kCurrentClass));
+        // But we type check it as a method on a generic class at runtime.
+        body += LoadLocal(arg_value);
+        body += LoadLocal(arg_pointer);
+        body += CheckNullOptimized(TokenPosition::kNoSource,
+                                   String::ZoneHandle(Z, function.name()));
+        // We pass the Pointer type argument as instantiator_type_args.
+        //
+        // Call sites to this recognized method are guaranteed to pass a
+        // Pointer<Pointer<X>> as RawParameterVariable(0). This function
+        // will takes a Pointer<X> object - for which we inspect the
+        // reified type on the argument.
+        //
+        // The following is safe to do, as (1) we are guaranteed to have a
+        // Pointer<Pointer<X>> as argument, and (2) the bound on the pointer
+        // type parameter guarantees X is an interface type.
+        body += LoadNativeField(
+            Slot::GetTypeArgumentsSlotFor(thread_, pointer_class));
+        body += NullConstant();  // function_type_args.
+        body += AssertAssignable(TokenPosition::kNoSource, pointer_type_arg,
+                                 Symbols::Empty());
+        body += Drop();
+      }
+
+      ASSERT(function.NumParameters() == 3);
+      body += LoadLocal(arg_pointer);  // Pointer.
+      body += CheckNullOptimized(TokenPosition::kNoSource,
+                                 String::ZoneHandle(Z, function.name()));
+      body += LoadNativeField(Slot::Pointer_c_memory_address());
+      body += UnboxTruncate(kUnboxedFfiIntPtr);
+      // We do Pointer.address + index * sizeOf<T> manually because LoadIndexed
+      // does not support Mint index arguments.
+      body += LoadLocal(arg_index);  // Index.
+      body += CheckNullOptimized(TokenPosition::kNoSource,
+                                 String::ZoneHandle(Z, function.name()));
+      body += UnboxTruncate(kUnboxedFfiIntPtr);
+      body += IntConstant(compiler::ffi::ElementSizeInBytes(ffi_type_arg_cid));
+      body += UnboxTruncate(kUnboxedFfiIntPtr);
+      // TODO(38831): Implement Shift for Uint32, and use that instead.
+      body +=
+          BinaryIntegerOp(Token::kMUL, kUnboxedFfiIntPtr, /* truncate= */ true);
+      body +=
+          BinaryIntegerOp(Token::kADD, kUnboxedFfiIntPtr, /* truncate= */ true);
+      body += ConvertIntptrToUntagged();
+      body += IntConstant(0);
+      body += LoadLocal(arg_value);  // Value.
+      body += CheckNullOptimized(TokenPosition::kNoSource,
+                                 String::ZoneHandle(Z, function.name()));
+      if (kind == MethodRecognizer::kFfiStorePointer) {
+        body += LoadNativeField(Slot::Pointer_c_memory_address());
+      } else if (kind == MethodRecognizer::kFfiStoreFloat ||
+                 kind == MethodRecognizer::kFfiStoreDouble) {
+        body += UnboxTruncate(kUnboxedDouble);
+        if (kind == MethodRecognizer::kFfiStoreFloat) {
+          body += DoubleToFloat();
+        }
+      } else {
+        body += UnboxTruncate(representation);
+      }
+      body += StoreIndexedTypedData(typed_data_cid);
+      body += NullConstant();
+    } break;
+    case MethodRecognizer::kFfiFromAddress: {
+      const auto class_table = thread_->isolate()->class_table();
+      ASSERT(class_table->HasValidClassAt(kFfiPointerCid));
+      const auto& pointer_class =
+          Class::ZoneHandle(H.zone(), class_table->At(kFfiPointerCid));
+
+      ASSERT(function.NumTypeParameters() == 1);
+      ASSERT(function.NumParameters() == 1);
+      body += LoadLocal(parsed_function_->RawTypeArgumentsVariable());
+      body += PushArgument();
+      body += AllocateObject(TokenPosition::kNoSource, pointer_class, 1);
+      body += LoadLocal(MakeTemporary());  // Duplicate Pointer.
+      body += LoadLocal(parsed_function_->RawParameterVariable(0));  // Address.
+      body += CheckNullOptimized(TokenPosition::kNoSource,
+                                 String::ZoneHandle(Z, function.name()));
+#if defined(TARGET_ARCH_IS_32_BIT)
+      // Truncate to 32 bits on 32 bit architecture.
+      body += UnboxTruncate(kUnboxedFfiIntPtr);
+      body += Box(kUnboxedFfiIntPtr);
+#endif  // defined(TARGET_ARCH_IS_32_BIT)
+      body += StoreInstanceField(TokenPosition::kNoSource,
+                                 Slot::Pointer_c_memory_address());
+    } break;
+    case MethodRecognizer::kFfiGetAddress: {
+      ASSERT(function.NumParameters() == 1);
+      body += LoadLocal(parsed_function_->RawParameterVariable(0));  // Pointer.
+      body += CheckNullOptimized(TokenPosition::kNoSource,
+                                 String::ZoneHandle(Z, function.name()));
+      body += LoadNativeField(Slot::Pointer_c_memory_address());
+    } break;
     default: {
       UNREACHABLE();
       break;
@@ -1210,44 +1463,37 @@
       !dst_type.IsVoidType()) {
     LocalVariable* top_of_stack = MakeTemporary();
     instructions += LoadLocal(top_of_stack);
-    instructions +=
-        AssertAssignable(TokenPosition::kNoSource, dst_type, dst_name, kind);
+    instructions += AssertAssignableLoadTypeArguments(TokenPosition::kNoSource,
+                                                      dst_type, dst_name, kind);
     instructions += Drop();
   }
   return instructions;
 }
 
-Fragment FlowGraphBuilder::AssertAssignable(TokenPosition position,
-                                            const AbstractType& dst_type,
-                                            const String& dst_name,
-                                            AssertAssignableInstr::Kind kind) {
+Fragment FlowGraphBuilder::AssertAssignableLoadTypeArguments(
+    TokenPosition position,
+    const AbstractType& dst_type,
+    const String& dst_name,
+    AssertAssignableInstr::Kind kind) {
   if (!I->should_emit_strong_mode_checks()) {
     return Fragment();
   }
 
   Fragment instructions;
-  Value* value = Pop();
 
   if (!dst_type.IsInstantiated(kCurrentClass)) {
     instructions += LoadInstantiatorTypeArguments();
   } else {
     instructions += NullConstant();
   }
-  Value* instantiator_type_args = Pop();
 
   if (!dst_type.IsInstantiated(kFunctions)) {
     instructions += LoadFunctionTypeArguments();
   } else {
     instructions += NullConstant();
   }
-  Value* function_type_args = Pop();
 
-  AssertAssignableInstr* instr = new (Z) AssertAssignableInstr(
-      position, value, instantiator_type_args, function_type_args, dst_type,
-      dst_name, GetNextDeoptId(), kind);
-  Push(instr);
-
-  instructions += Fragment(instr);
+  instructions += AssertAssignable(position, dst_type, dst_name, kind);
 
   return instructions;
 }
@@ -1936,8 +2182,8 @@
   AbstractType& return_type = AbstractType::Handle(function.result_type());
   if (!return_type.IsDynamicType() && !return_type.IsVoidType() &&
       !return_type.IsObjectType()) {
-    body += AssertAssignable(TokenPosition::kNoSource, return_type,
-                             Symbols::Empty());
+    body += AssertAssignableLoadTypeArguments(TokenPosition::kNoSource,
+                                              return_type, Symbols::Empty());
   }
   body += Return(TokenPosition::kNoSource);
 
@@ -2435,7 +2681,8 @@
     body += NullConstant();
   } else {
     const Representation from_rep = native_representation;
-    const Representation to_rep = compiler::ffi::TypeRepresentation(ffi_type);
+    const Representation to_rep =
+        compiler::ffi::TypeRepresentation(ffi_type.type_class_id());
     if (from_rep != to_rep) {
       body += BitCast(from_rep, to_rep);
     } else {
@@ -2453,15 +2700,15 @@
   Fragment body;
 
   // Check for 'null'.
-  body += LoadLocal(MakeTemporary());
-  body <<= new (Z) CheckNullInstr(Pop(), String::ZoneHandle(Z, function.name()),
-                                  GetNextDeoptId(), TokenPosition::kNoSource);
+  body += CheckNullOptimized(TokenPosition::kNoSource,
+                             String::ZoneHandle(Z, function.name()));
 
   if (compiler::ffi::NativeTypeIsPointer(ffi_type)) {
     body += LoadNativeField(Slot::Pointer_c_memory_address());
     body += UnboxTruncate(kUnboxedFfiIntPtr);
   } else {
-    Representation from_rep = compiler::ffi::TypeRepresentation(ffi_type);
+    Representation from_rep =
+        compiler::ffi::TypeRepresentation(ffi_type.type_class_id());
     body += UnboxTruncate(from_rep);
 
     Representation to_rep = native_representation;
diff --git a/runtime/vm/compiler/frontend/kernel_to_il.h b/runtime/vm/compiler/frontend/kernel_to_il.h
index 3775000..ca4e786 100644
--- a/runtime/vm/compiler/frontend/kernel_to_il.h
+++ b/runtime/vm/compiler/frontend/kernel_to_il.h
@@ -82,6 +82,7 @@
   Fragment NativeFunctionBody(const Function& function,
                               LocalVariable* first_parameter);
 
+  // Every recognized method has a body expressed in IL.
   bool IsRecognizedMethodForFlowGraph(const Function& function);
   FlowGraph* BuildGraphOfRecognizedMethod(const Function& function);
 
@@ -164,7 +165,7 @@
       const String& dst_name,
       AssertAssignableInstr::Kind kind = AssertAssignableInstr::kUnknown);
 
-  Fragment AssertAssignable(
+  Fragment AssertAssignableLoadTypeArguments(
       TokenPosition position,
       const AbstractType& dst_type,
       const String& dst_name,
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h
index 4e83641..de53d78 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.h
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h
@@ -755,6 +755,7 @@
   enum Flag {
     kExternal = 1 << 0,
     kSynthetic = 1 << 1,
+    kIsNonNullableByDefault = 1 << 2,
   };
 
   explicit LibraryHelper(KernelReaderHelper* helper, uint32_t binary_version)
@@ -771,6 +772,9 @@
 
   bool IsExternal() const { return (flags_ & kExternal) != 0; }
   bool IsSynthetic() const { return (flags_ & kSynthetic) != 0; }
+  bool IsNonNullableByDefault() const {
+    return (flags_ & kIsNonNullableByDefault) != 0;
+  }
 
   uint8_t flags_ = 0;
   NameIndex canonical_name_;
diff --git a/runtime/vm/compiler/frontend/prologue_builder.cc b/runtime/vm/compiler/frontend/prologue_builder.cc
index d9ce861..ee1f4ee 100644
--- a/runtime/vm/compiler/frontend/prologue_builder.cc
+++ b/runtime/vm/compiler/frontend/prologue_builder.cc
@@ -420,6 +420,7 @@
 
 Fragment PrologueBuilder::BuildTypeArgumentsHandling(JoinEntryInstr* nsm) {
   LocalVariable* type_args_var = parsed_function_->RawTypeArgumentsVariable();
+  ASSERT(type_args_var != nullptr);
 
   Fragment handling;
 
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index 848564d..9071252 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -145,6 +145,32 @@
   V(::, _abi, FfiAbi, 0xf2e89620)                                              \
   V(::, _asFunctionInternal, FfiAsFunctionInternal, 0x92a67518)                \
   V(::, _nativeCallbackFunction, FfiNativeCallbackFunction, 0x59cc5edb)        \
+  V(::, _loadInt8, FfiLoadInt8, 0x9b1e4a8d)                                    \
+  V(::, _loadInt16, FfiLoadInt16, 0x2824dc24)                                  \
+  V(::, _loadInt32, FfiLoadInt32, 0x3f9bf49d)                                  \
+  V(::, _loadInt64, FfiLoadInt64, 0xbb4e2186)                                  \
+  V(::, _loadUint8, FfiLoadUint8, 0xc93d1241)                                  \
+  V(::, _loadUint16, FfiLoadUint16, 0x4bc4c8ae)                                \
+  V(::, _loadUint32, FfiLoadUint32, 0x5fd2e17c)                                \
+  V(::, _loadUint64, FfiLoadUint64, 0xec4e4e0a)                                \
+  V(::, _loadIntPtr, FfiLoadIntPtr, 0x1ad8e69f)                                \
+  V(::, _loadFloat, FfiLoadFloat, 0x234b92dc)                                  \
+  V(::, _loadDouble, FfiLoadDouble, 0x97c755b3)                                \
+  V(::, _loadPointer, FfiLoadPointer, 0xd478c108)                              \
+  V(::, _storeInt8, FfiStoreInt8, 0x9a637adf)                                  \
+  V(::, _storeInt16, FfiStoreInt16, 0x7c5ad40b)                                \
+  V(::, _storeInt32, FfiStoreInt32, 0xc729a9da)                                \
+  V(::, _storeInt64, FfiStoreInt64, 0x748af071)                                \
+  V(::, _storeUint8, FfiStoreUint8, 0xea22235e)                                \
+  V(::, _storeUint16, FfiStoreUint16, 0x0c61dd74)                              \
+  V(::, _storeUint32, FfiStoreUint32, 0x32962fcb)                              \
+  V(::, _storeUint64, FfiStoreUint64, 0xe55a10c2)                              \
+  V(::, _storeIntPtr, FfiStoreIntPtr, 0xc75ef10f)                              \
+  V(::, _storeFloat, FfiStoreFloat, 0x34a22e07)                                \
+  V(::, _storeDouble, FfiStoreDouble, 0x09226ca7)                              \
+  V(::, _storePointer, FfiStorePointer, 0x2641a44b)                            \
+  V(::, _fromAddress, FfiFromAddress, 0x8eb74eb8)                              \
+  V(Pointer, get:address, FfiGetAddress, 0x29a505a1)                           \
 
 // List of intrinsics:
 // (class-name, function-name, intrinsification method, fingerprint).
diff --git a/runtime/vm/constants_arm.cc b/runtime/vm/constants_arm.cc
index 308ce00..a4a0dd7 100644
--- a/runtime/vm/constants_arm.cc
+++ b/runtime/vm/constants_arm.cc
@@ -7,6 +7,8 @@
 
 namespace arch_arm {
 
+using dart::bit_cast;
+
 const char* cpu_reg_names[kNumberOfCpuRegisters] = {
     "r0", "r1",  "r2", "r3", "r4", "r5", "r6", "r7",
     "r8", "ctx", "pp", "fp", "ip", "sp", "lr", "pc",
@@ -25,4 +27,116 @@
 // one element to appease MSVC.
 const FpuRegister CallingConventions::FpuArgumentRegisters[] = {Q0};
 
+float ReciprocalEstimate(float a) {
+  // From the ARM Architecture Reference Manual A2-85.
+  if (isinf(a) || (fabs(a) >= exp2f(126)))
+    return a >= 0.0f ? 0.0f : -0.0f;
+  else if (a == 0.0f)
+    return 1.0f / a;
+  else if (isnan(a))
+    return a;
+
+  uint32_t a_bits = bit_cast<uint32_t, float>(a);
+  // scaled = '0011 1111 1110' : a<22:0> : Zeros(29)
+  uint64_t scaled = (static_cast<uint64_t>(0x3fe) << 52) |
+                    ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
+  // result_exp = 253 - UInt(a<30:23>)
+  int32_t result_exp = 253 - ((a_bits >> 23) & 0xff);
+  ASSERT((result_exp >= 1) && (result_exp <= 252));
+
+  double scaled_d = bit_cast<double, uint64_t>(scaled);
+  ASSERT((scaled_d >= 0.5) && (scaled_d < 1.0));
+
+  // a in units of 1/512 rounded down.
+  int32_t q = static_cast<int32_t>(scaled_d * 512.0);
+  // reciprocal r.
+  double r = 1.0 / ((static_cast<double>(q) + 0.5) / 512.0);
+  // r in units of 1/256 rounded to nearest.
+  int32_t s = static_cast<int32_t>(256.0 * r + 0.5);
+  double estimate = static_cast<double>(s) / 256.0;
+  ASSERT((estimate >= 1.0) && (estimate <= (511.0 / 256.0)));
+
+  // result = sign : result_exp<7:0> : estimate<51:29>
+  int32_t result_bits =
+      (a_bits & 0x80000000) | ((result_exp & 0xff) << 23) |
+      ((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff);
+  return bit_cast<float, int32_t>(result_bits);
+}
+
+float ReciprocalStep(float op1, float op2) {
+  float p;
+  if ((isinf(op1) && op2 == 0.0f) || (op1 == 0.0f && isinf(op2))) {
+    p = 0.0f;
+  } else {
+    p = op1 * op2;
+  }
+  return 2.0f - p;
+}
+
+float ReciprocalSqrtEstimate(float a) {
+  // From the ARM Architecture Reference Manual A2-87.
+  if (a < 0.0f)
+    return NAN;
+  else if (isinf(a) || (fabs(a) >= exp2f(126)))
+    return 0.0f;
+  else if (a == 0.0)
+    return 1.0f / a;
+  else if (isnan(a))
+    return a;
+
+  uint32_t a_bits = bit_cast<uint32_t, float>(a);
+  uint64_t scaled;
+  if (((a_bits >> 23) & 1) != 0) {
+    // scaled = '0 01111111101' : operand<22:0> : Zeros(29)
+    scaled = (static_cast<uint64_t>(0x3fd) << 52) |
+             ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
+  } else {
+    // scaled = '0 01111111110' : operand<22:0> : Zeros(29)
+    scaled = (static_cast<uint64_t>(0x3fe) << 52) |
+             ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
+  }
+  // result_exp = (380 - UInt(operand<30:23>) DIV 2;
+  int32_t result_exp = (380 - ((a_bits >> 23) & 0xff)) / 2;
+
+  double scaled_d = bit_cast<double, uint64_t>(scaled);
+  ASSERT((scaled_d >= 0.25) && (scaled_d < 1.0));
+
+  double r;
+  if (scaled_d < 0.5) {
+    // range 0.25 <= a < 0.5
+
+    // a in units of 1/512 rounded down.
+    int32_t q0 = static_cast<int32_t>(scaled_d * 512.0);
+    // reciprocal root r.
+    r = 1.0 / sqrt((static_cast<double>(q0) + 0.5) / 512.0);
+  } else {
+    // range 0.5 <= a < 1.0
+
+    // a in units of 1/256 rounded down.
+    int32_t q1 = static_cast<int32_t>(scaled_d * 256.0);
+    // reciprocal root r.
+    r = 1.0 / sqrt((static_cast<double>(q1) + 0.5) / 256.0);
+  }
+  // r in units of 1/256 rounded to nearest.
+  int32_t s = static_cast<int>(256.0 * r + 0.5);
+  double estimate = static_cast<double>(s) / 256.0;
+  ASSERT((estimate >= 1.0) && (estimate <= (511.0 / 256.0)));
+
+  // result = 0 : result_exp<7:0> : estimate<51:29>
+  int32_t result_bits =
+      ((result_exp & 0xff) << 23) |
+      ((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff);
+  return bit_cast<float, int32_t>(result_bits);
+}
+
+float ReciprocalSqrtStep(float op1, float op2) {
+  float p;
+  if ((isinf(op1) && op2 == 0.0f) || (op1 == 0.0f && isinf(op2))) {
+    p = 0.0f;
+  } else {
+    p = op1 * op2;
+  }
+  return (3.0f - p) / 2.0f;
+}
+
 }  // namespace arch_arm
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index b8fc2f1..73ffe5d 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -822,6 +822,16 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(Instr);
 };
 
+// Floating-point reciprocal estimate and step (see pages A2-85 and A2-86 of
+// ARM Architecture Reference Manual ARMv7-A edition).
+float ReciprocalEstimate(float op);
+float ReciprocalStep(float op1, float op2);
+
+// Floating-point reciprocal square root estimate and step (see pages A2-87 to
+// A2-90 of ARM Architecture Reference Manual ARMv7-A edition).
+float ReciprocalSqrtEstimate(float op);
+float ReciprocalSqrtStep(float op1, float op2);
+
 }  // namespace arch_arm
 
 #endif  // RUNTIME_VM_CONSTANTS_ARM_H_
diff --git a/runtime/vm/constants_kbc.h b/runtime/vm/constants_kbc.h
index a4b5d21..ff0d8b4 100644
--- a/runtime/vm/constants_kbc.h
+++ b/runtime/vm/constants_kbc.h
@@ -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 = 22;
+  static const intptr_t kMaxSupportedBytecodeFormatVersion = 23;
 
   enum Opcode {
 #define DECLARE_BYTECODE(name, encoding, kind, op1, op2, op3) k##name,
@@ -918,6 +918,16 @@
     return DecodeOpcode(instr) == KernelBytecode::kCheckStack;
   }
 
+  DART_FORCE_INLINE static bool IsCheckFunctionTypeArgs(const KBCInstr* instr) {
+    switch (DecodeOpcode(instr)) {
+      case KernelBytecode::kCheckFunctionTypeArgs:
+      case KernelBytecode::kCheckFunctionTypeArgs_Wide:
+        return true;
+      default:
+        return false;
+    }
+  }
+
   DART_FORCE_INLINE static bool IsEntryOpcode(const KBCInstr* instr) {
     switch (DecodeOpcode(instr)) {
       case KernelBytecode::kEntry:
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 4a89518..35e6f8d 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -210,6 +210,7 @@
   start_time_micros_ = OS::GetCurrentMonotonicMicros();
   VirtualMemory::Init();
   OSThread::Init();
+  Zone::Init();
 #if defined(SUPPORT_TIMELINE)
   Timeline::Init();
   TimelineDurationScope tds(Timeline::GetVMStream(), "Dart::Init");
@@ -589,6 +590,14 @@
   Object::Cleanup();
   SemiSpace::Cleanup();
   StubCode::Cleanup();
+#if defined(SUPPORT_TIMELINE)
+  if (FLAG_trace_shutdown) {
+    OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Shutting down timeline\n",
+                 UptimeMillis());
+  }
+  Timeline::Cleanup();
+#endif
+  Zone::Cleanup();
   // Delete the current thread's TLS and set it's TLS to null.
   // If it is the last thread then the destructor would call
   // OSThread::Cleanup.
@@ -605,13 +614,6 @@
                  UptimeMillis());
   }
   NOT_IN_PRODUCT(CodeObservers::Cleanup());
-#if defined(SUPPORT_TIMELINE)
-  if (FLAG_trace_shutdown) {
-    OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Shutting down timeline\n",
-                 UptimeMillis());
-  }
-  Timeline::Cleanup();
-#endif
   OS::Cleanup();
   if (FLAG_trace_shutdown) {
     OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Done\n", UptimeMillis());
diff --git a/runtime/vm/heap/become.h b/runtime/vm/heap/become.h
index 1b27798..5e98eba 100644
--- a/runtime/vm/heap/become.h
+++ b/runtime/vm/heap/become.h
@@ -5,6 +5,7 @@
 #ifndef RUNTIME_VM_HEAP_BECOME_H_
 #define RUNTIME_VM_HEAP_BECOME_H_
 
+#include "platform/atomic.h"
 #include "vm/allocation.h"
 #include "vm/raw_object.h"
 
@@ -52,7 +53,7 @@
 
  private:
   // This layout mirrors the layout of RawObject.
-  uint32_t tags_;
+  RelaxedAtomic<uint32_t> tags_;
 #if defined(HASH_IN_OBJECT_HEADER)
   uint32_t hash_;
 #endif
diff --git a/runtime/vm/heap/compactor.cc b/runtime/vm/heap/compactor.cc
index c327ce3..0c50ab0 100644
--- a/runtime/vm/heap/compactor.cc
+++ b/runtime/vm/heap/compactor.cc
@@ -4,6 +4,7 @@
 
 #include "vm/heap/compactor.h"
 
+#include "platform/atomic.h"
 #include "vm/globals.h"
 #include "vm/heap/become.h"
 #include "vm/heap/heap.h"
@@ -126,7 +127,7 @@
   CompactorTask(Isolate* isolate,
                 GCCompactor* compactor,
                 ThreadBarrier* barrier,
-                intptr_t* next_forwarding_task,
+                RelaxedAtomic<intptr_t>* next_forwarding_task,
                 HeapPage* head,
                 HeapPage** tail,
                 FreeList* freelist)
@@ -152,7 +153,7 @@
   Isolate* isolate_;
   GCCompactor* compactor_;
   ThreadBarrier* barrier_;
-  intptr_t* next_forwarding_task_;
+  RelaxedAtomic<intptr_t>* next_forwarding_task_;
   HeapPage* head_;
   HeapPage** tail_;
   FreeList* freelist_;
@@ -243,7 +244,7 @@
   {
     ThreadBarrier barrier(num_tasks + 1, heap_->barrier(),
                           heap_->barrier_done());
-    intptr_t next_forwarding_task = 0;
+    RelaxedAtomic<intptr_t> next_forwarding_task = {0};
 
     for (intptr_t task_index = 0; task_index < num_tasks; task_index++) {
       Dart::thread_pool()->Run<CompactorTask>(
@@ -370,8 +371,7 @@
 
     bool more_forwarding_tasks = true;
     while (more_forwarding_tasks) {
-      intptr_t forwarding_task =
-          AtomicOperations::FetchAndIncrement(next_forwarding_task_);
+      intptr_t forwarding_task = next_forwarding_task_->fetch_add(1u);
       switch (forwarding_task) {
         case 0: {
           TIMELINE_FUNCTION_GC_DURATION(thread, "ForwardLargePages");
diff --git a/runtime/vm/heap/freelist.h b/runtime/vm/heap/freelist.h
index 9fac19d..09ad006 100644
--- a/runtime/vm/heap/freelist.h
+++ b/runtime/vm/heap/freelist.h
@@ -6,6 +6,7 @@
 #define RUNTIME_VM_HEAP_FREELIST_H_
 
 #include "platform/assert.h"
+#include "platform/atomic.h"
 #include "vm/allocation.h"
 #include "vm/bit_set.h"
 #include "vm/os_thread.h"
@@ -56,7 +57,7 @@
 
  private:
   // This layout mirrors the layout of RawObject.
-  uint32_t tags_;
+  RelaxedAtomic<uint32_t> tags_;
 #if defined(HASH_IN_OBJECT_HEADER)
   uint32_t hash_;
 #endif
diff --git a/runtime/vm/heap/heap_test.cc b/runtime/vm/heap/heap_test.cc
index a456287..6ffad95 100644
--- a/runtime/vm/heap/heap_test.cc
+++ b/runtime/vm/heap/heap_test.cc
@@ -86,9 +86,9 @@
   }
 
   static void DumpClassHeapStats(ClassHeapStats* stats) {
-    OS::PrintErr("%" Pd " ", stats->recent.new_count);
-    OS::PrintErr("%" Pd " ", stats->post_gc.new_count);
-    OS::PrintErr("%" Pd " ", stats->pre_gc.new_count);
+    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");
   }
 };
diff --git a/runtime/vm/heap/marker.cc b/runtime/vm/heap/marker.cc
index 5558aa8..2e950e9 100644
--- a/runtime/vm/heap/marker.cc
+++ b/runtime/vm/heap/marker.cc
@@ -4,6 +4,7 @@
 
 #include "vm/heap/marker.h"
 
+#include "platform/atomic.h"
 #include "vm/allocation.h"
 #include "vm/dart_api_state.h"
 #include "vm/heap/pages.h"
@@ -548,7 +549,7 @@
                    MarkingStack* marking_stack,
                    ThreadBarrier* barrier,
                    SyncMarkingVisitor* visitor,
-                   uintptr_t* num_busy)
+                   RelaxedAtomic<uintptr_t>* num_busy)
       : marker_(marker),
         isolate_(isolate),
         marking_stack_(marking_stack),
@@ -576,25 +577,24 @@
 
           // I can't find more work right now. If no other task is busy,
           // then there will never be more work (NB: 1 is *before* decrement).
-          if (AtomicOperations::FetchAndDecrement(num_busy_) == 1) break;
+          if (num_busy_->fetch_sub(1u) == 1) break;
 
           // Wait for some work to appear.
           // TODO(iposva): Replace busy-waiting with a solution using Monitor,
           // and redraw the boundaries between stack/visitor/task as needed.
-          while (marking_stack_->IsEmpty() &&
-                 AtomicOperations::LoadRelaxed(num_busy_) > 0) {
+          while (marking_stack_->IsEmpty() && num_busy_->load() > 0) {
           }
 
           // If no tasks are busy, there will never be more work.
-          if (AtomicOperations::LoadRelaxed(num_busy_) == 0) break;
+          if (num_busy_->load() == 0) break;
 
           // I saw some work; get busy and compete for it.
-          AtomicOperations::FetchAndIncrement(num_busy_);
+          num_busy_->fetch_add(1u);
         } while (true);
         // Wait for all markers to stop.
         barrier_->Sync();
 #if defined(DEBUG)
-        ASSERT(AtomicOperations::LoadRelaxed(num_busy_) == 0);
+        ASSERT(num_busy_->load() == 0);
         // Caveat: must not allow any marker to continue past the barrier
         // before we checked num_busy, otherwise one of them might rush
         // ahead and increment it.
@@ -605,7 +605,7 @@
         more_to_mark = visitor_->ProcessPendingWeakProperties();
         if (more_to_mark) {
           // We have more work to do. Notify others.
-          AtomicOperations::FetchAndIncrement(num_busy_);
+          num_busy_->fetch_add(1u);
         }
 
         // Wait for all other markers to finish processing their pending
@@ -613,10 +613,10 @@
         // Caveat: we need two barriers here to make this decision in lock step
         // between all markers and the main thread.
         barrier_->Sync();
-        if (!more_to_mark && (AtomicOperations::LoadRelaxed(num_busy_) > 0)) {
+        if (!more_to_mark && (num_busy_->load() > 0)) {
           // All markers continue to mark as long as any single marker has
           // some work to do.
-          AtomicOperations::FetchAndIncrement(num_busy_);
+          num_busy_->fetch_add(1u);
           more_to_mark = true;
         }
         barrier_->Sync();
@@ -650,7 +650,7 @@
   MarkingStack* marking_stack_;
   ThreadBarrier* barrier_;
   SyncMarkingVisitor* visitor_;
-  uintptr_t* num_busy_;
+  RelaxedAtomic<uintptr_t>* num_busy_;
 
   DISALLOW_COPY_AND_ASSIGN(ParallelMarkTask);
 };
@@ -851,7 +851,7 @@
                             heap_->barrier_done());
       ResetRootSlices();
       // Used to coordinate draining among tasks; all start out as 'busy'.
-      uintptr_t num_busy = num_tasks;
+      RelaxedAtomic<uintptr_t> num_busy(num_tasks);
       // Phase 1: Iterate over roots and drain marking stack in tasks.
       for (intptr_t i = 0; i < num_tasks; ++i) {
         SyncMarkingVisitor* visitor;
@@ -872,7 +872,7 @@
         // Wait for all markers to stop.
         barrier.Sync();
 #if defined(DEBUG)
-        ASSERT(AtomicOperations::LoadRelaxed(&num_busy) == 0);
+        ASSERT(num_busy.load() == 0);
         // Caveat: must not allow any marker to continue past the barrier
         // before we checked num_busy, otherwise one of them might rush
         // ahead and increment it.
@@ -884,7 +884,7 @@
         // Note: we need to have two barriers here because we want all markers
         // and main thread to make decisions in lock step.
         barrier.Sync();
-        more_to_mark = AtomicOperations::LoadRelaxed(&num_busy) > 0;
+        more_to_mark = num_busy.load() > 0;
         barrier.Sync();
       } while (more_to_mark);
 
diff --git a/runtime/vm/heap/pages.h b/runtime/vm/heap/pages.h
index 3341eec..b723b63 100644
--- a/runtime/vm/heap/pages.h
+++ b/runtime/vm/heap/pages.h
@@ -5,6 +5,7 @@
 #ifndef RUNTIME_VM_HEAP_PAGES_H_
 #define RUNTIME_VM_HEAP_PAGES_H_
 
+#include "platform/atomic.h"
 #include "vm/globals.h"
 #include "vm/heap/freelist.h"
 #include "vm/heap/spaces.h"
@@ -375,8 +376,7 @@
 #endif  // PRODUCT
 
   void AllocateBlack(intptr_t size) {
-    AtomicOperations::IncrementBy(&allocated_black_in_words_,
-                                  size >> kWordSizeLog2);
+    allocated_black_in_words_.fetch_add(size >> kWordSizeLog2);
   }
 
   void AllocateExternal(intptr_t cid, intptr_t size);
@@ -512,7 +512,7 @@
   // NOTE: The capacity component of usage_ is updated by the concurrent
   // sweeper. Use (Increase)CapacityInWords(Locked) for thread-safe access.
   SpaceUsage usage_;
-  intptr_t allocated_black_in_words_;
+  RelaxedAtomic<intptr_t> allocated_black_in_words_;
 
   // Keep track of running MarkSweep tasks.
   mutable Monitor tasks_lock_;
diff --git a/runtime/vm/image_snapshot.cc b/runtime/vm/image_snapshot.cc
index de688a1..cd95108 100644
--- a/runtime/vm/image_snapshot.cc
+++ b/runtime/vm/image_snapshot.cc
@@ -185,11 +185,11 @@
 }
 
 #if defined(IS_SIMARM_X64)
-static intptr_t StackMapSizeInSnapshot(intptr_t len_in_bits) {
-  const intptr_t len_in_bytes =
-      Utils::RoundUp(len_in_bits, kBitsPerByte) / kBitsPerByte;
+static intptr_t CompressedStackMapsSizeInSnapshot(intptr_t payload_size) {
+  // We do not need to round the non-payload size up to a word boundary because
+  // currently sizeof(RawCompressedStackMaps) is 12, even on 64-bit.
   const intptr_t unrounded_size_in_bytes =
-      2 * compiler::target::kWordSize + len_in_bytes;
+      compiler::target::kWordSize + sizeof(uint32_t) + payload_size;
   return Utils::RoundUp(unrounded_size_in_bytes,
                         compiler::target::ObjectAlignment::kObjectAlignment);
 }
@@ -232,9 +232,10 @@
   const classid_t cid = raw_object->GetClassId();
 
   switch (cid) {
-    case kStackMapCid: {
-      RawStackMap* raw_map = static_cast<RawStackMap*>(raw_object);
-      return StackMapSizeInSnapshot(raw_map->ptr()->length_);
+    case kCompressedStackMapsCid: {
+      RawCompressedStackMaps* raw_maps =
+          static_cast<RawCompressedStackMaps*>(raw_object);
+      return CompressedStackMapsSizeInSnapshot(raw_maps->ptr()->payload_size_);
     }
     case kOneByteStringCid:
     case kTwoByteStringCid: {
@@ -431,23 +432,22 @@
 #endif
 
 #if defined(IS_SIMARM_X64)
-    if (obj.IsStackMap()) {
-      const StackMap& map = StackMap::Cast(obj);
+    if (obj.IsCompressedStackMaps()) {
+      const CompressedStackMaps& map = CompressedStackMaps::Cast(obj);
 
       // Header layout is the same between 32-bit and 64-bit architecture, but
       // we need to recalcuate the size in words.
-      const intptr_t len_in_bits = map.Length();
-      const intptr_t len_in_bytes =
-          Utils::RoundUp(len_in_bits, kBitsPerByte) / kBitsPerByte;
-      const intptr_t size_in_bytes = StackMapSizeInSnapshot(len_in_bits);
+      const intptr_t payload_size = map.payload_size();
+      const intptr_t size_in_bytes =
+          CompressedStackMapsSizeInSnapshot(payload_size);
       marked_tags = RawObject::SizeTag::update(size_in_bytes * 2, marked_tags);
 
       stream->WriteTargetWord(marked_tags);
-      stream->WriteFixed<uint16_t>(map.Length());
-      stream->WriteFixed<uint16_t>(map.SlowPathBitCount());
-      stream->WriteBytes(map.raw()->ptr()->data(), len_in_bytes);
+      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->WriteBytes(map.raw()->ptr()->data(), payload_size);
       stream->Align(compiler::target::ObjectAlignment::kObjectAlignment);
-
     } else if (obj.IsString()) {
       const String& str = String::Cast(obj);
       RELEASE_ASSERT(String::GetCachedHash(str.raw()) != 0);
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index 2ed72dd..24c4c01 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -20,7 +20,7 @@
 
 // Both version numbers are inclusive.
 static const uint32_t kMinSupportedKernelFormatVersion = 18;
-static const uint32_t kMaxSupportedKernelFormatVersion = 34;
+static const uint32_t kMaxSupportedKernelFormatVersion = 35;
 
 // Keep in sync with package:kernel/lib/binary/tag.dart
 #define KERNEL_TAG_LIST(V)                                                     \
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index 0b21e53..fce72a9 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -1022,6 +1022,8 @@
   ASSERT(!library_helper.IsExternal() || library.Loaded());
   if (library.Loaded()) return library.raw();
 
+  library.set_is_nnbd(library_helper.IsNonNullableByDefault());
+
   library_kernel_data_ = helper_.reader_.ExternalDataFromTo(
       library_kernel_offset_, library_kernel_offset_ + library_size);
   library.set_kernel_data(library_kernel_data_);
@@ -2345,6 +2347,7 @@
   initializer_fun.set_end_token_pos(field.end_token_pos());
   initializer_fun.set_accessor_field(field);
   initializer_fun.InheritBinaryDeclarationFrom(field);
+  initializer_fun.set_is_extension_member(field.is_extension_member());
   field.SetInitializerFunction(initializer_fun);
   return initializer_fun.raw();
 }
diff --git a/runtime/vm/native_entry.cc b/runtime/vm/native_entry.cc
index fbf0c55..769fb1b 100644
--- a/runtime/vm/native_entry.cc
+++ b/runtime/vm/native_entry.cc
@@ -140,7 +140,7 @@
     Dart_NativeFunction func) {
   VERIFY_ON_TRANSITION;
   NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
-  /* Tell MemorySanitizer 'arguments' is initialized by generated code. */
+  // Tell MemorySanitizer 'arguments' is initialized by generated code.
   MSAN_UNPOISON(arguments, sizeof(*arguments));
   Thread* thread = arguments->thread();
   ASSERT(thread->execution_state() == Thread::kThreadInGenerated);
@@ -177,7 +177,7 @@
     Dart_NativeFunction func) {
   VERIFY_ON_TRANSITION;
   NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
-  /* Tell MemorySanitizer 'arguments' is initialized by generated code. */
+  // Tell MemorySanitizer 'arguments' is initialized by generated code.
   MSAN_UNPOISON(arguments, sizeof(*arguments));
   Thread* thread = arguments->thread();
   ASSERT(thread->execution_state() == Thread::kThreadInGenerated);
@@ -238,7 +238,7 @@
   CHECK_STACK_ALIGNMENT;
   VERIFY_ON_TRANSITION;
   NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
-  /* Tell MemorySanitizer 'arguments' is initialized by generated code. */
+  // Tell MemorySanitizer 'arguments' is initialized by generated code.
   MSAN_UNPOISON(arguments, sizeof(*arguments));
   TRACE_NATIVE_CALL("%s", "LinkNative");
 
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index e5cdec3..ca5c1b5 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -104,7 +104,7 @@
 RawArray* SubtypeTestCache::cached_array_;
 
 cpp_vtable Object::handle_vtable_ = 0;
-cpp_vtable Object::builtin_vtables_[kNumPredefinedCids] = {0};
+RelaxedAtomic<cpp_vtable> Object::builtin_vtables_[kNumPredefinedCids] = {};
 cpp_vtable Smi::handle_vtable_ = 0;
 
 // These are initialized to a value that will force a illegal memory access if
@@ -153,7 +153,8 @@
 RawClass* Object::pc_descriptors_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
 RawClass* Object::code_source_map_class_ =
     reinterpret_cast<RawClass*>(RAW_NULL);
-RawClass* Object::stackmap_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+RawClass* Object::compressed_stackmaps_class_ =
+    reinterpret_cast<RawClass*>(RAW_NULL);
 RawClass* Object::var_descriptors_class_ =
     reinterpret_cast<RawClass*>(RAW_NULL);
 RawClass* Object::exception_handlers_class_ =
@@ -252,7 +253,15 @@
 //   _MyClass@6328321. -> _MyClass
 //   _MyClass@6328321.named -> _MyClass.named
 //
-RawString* String::ScrubName(const String& name) {
+// For extension methods the following demangling is done
+//   ext|func -> ext.func (instance extension method)
+//   ext|get#prop -> ext.prop (instance extension getter)
+//   ext|set#prop -> ext.prop= (instance extension setter)
+//   ext|sfunc -> ext.sfunc (static extension method)
+//   get:ext|sprop -> ext.sprop (static extension getter)
+//   set:ext|sprop -> ext.sprop= (static extension setter)
+//
+RawString* String::ScrubName(const String& name, bool is_extension) {
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
 
@@ -266,7 +275,8 @@
   const char* cname = name.ToCString();
   ASSERT(strlen(cname) == static_cast<size_t>(name.Length()));
   const intptr_t name_len = name.Length();
-  // First remove all private name mangling.
+  // First remove all private name mangling and if 'is_extension' is true
+  // substitute the first '|' character with '.'.
   intptr_t start_pos = 0;
   GrowableArray<const char*> unmangled_segments;
   intptr_t sum_segment_len = 0;
@@ -286,6 +296,15 @@
       }
       start_pos = i;
       i--;  // Account for for-loop increment.
+    } else if (is_extension && cname[i] == '|') {
+      // Append the current segment to the unmangled name.
+      const intptr_t segment_len = i - start_pos;
+      AppendSubString(zone, &unmangled_segments, cname, start_pos, segment_len);
+      // Append the '.' character (replaces '|' with '.').
+      AppendSubString(zone, &unmangled_segments, ".", 0, 1);
+      start_pos = i + 1;
+      // Account for length of segments added so far.
+      sum_segment_len += (segment_len + 1);
     }
   }
 
@@ -305,13 +324,41 @@
     unmangled_name = MergeSubStrings(zone, unmangled_segments, sum_segment_len);
   }
 
-#if !defined(DART_PRECOMPILED_RUNTIME)
-  intptr_t len = sum_segment_len;
+  unmangled_segments.Clear();
   intptr_t start = 0;
-  intptr_t dot_pos = -1;  // Position of '.' in the name, if any.
+  intptr_t final_len = 0;
+  intptr_t len = sum_segment_len;
   bool is_setter = false;
+  if (is_extension) {
+    // First scan till we see the '.' character.
+    for (intptr_t i = 0; i < len; i++) {
+      if (unmangled_name[i] == '.') {
+        intptr_t slen = i + 1;
+        intptr_t plen = slen - start;
+        AppendSubString(zone, &unmangled_segments, unmangled_name, start, plen);
+        final_len = plen;
+        unmangled_name += slen;
+        len -= slen;
+        break;
+      } else if (unmangled_name[i] == ':') {
+        if (start != 0) {
+          // Reset and break.
+          start = 0;
+          is_setter = false;
+          break;
+        }
+        if (unmangled_name[0] == 's') {
+          is_setter = true;
+        }
+        start = i + 1;
+      }
+    }
+  }
+  intptr_t dot_pos = -1;  // Position of '.' in the name, if any.
+  start = 0;
   for (intptr_t i = start; i < len; i++) {
-    if (unmangled_name[i] == ':') {
+    if (unmangled_name[i] == ':' ||
+        (is_extension && unmangled_name[i] == '#')) {
       if (start != 0) {
         // Reset and break.
         start = 0;
@@ -320,6 +367,7 @@
       }
       ASSERT(start == 0);  // Only one : is possible in getters or setters.
       if (unmangled_name[0] == 's') {
+        ASSERT(!is_setter);
         is_setter = true;
       }
       start = i + 1;
@@ -335,7 +383,7 @@
     }
   }
 
-  if ((start == 0) && (dot_pos == -1)) {
+  if (!is_extension && (start == 0) && (dot_pos == -1)) {
     // This unmangled_name is fine as it is.
     return Symbols::New(thread, unmangled_name, sum_segment_len);
   }
@@ -343,9 +391,9 @@
   // Drop the trailing dot if needed.
   intptr_t end = ((dot_pos + 1) == len) ? dot_pos : len;
 
-  unmangled_segments.Clear();
-  intptr_t final_len = end - start;
-  AppendSubString(zone, &unmangled_segments, unmangled_name, start, final_len);
+  intptr_t substr_len = end - start;
+  final_len += substr_len;
+  AppendSubString(zone, &unmangled_segments, unmangled_name, start, substr_len);
   if (is_setter) {
     const char* equals = Symbols::Equals().ToCString();
     const intptr_t equals_len = strlen(equals);
@@ -354,22 +402,50 @@
   }
 
   unmangled_name = MergeSubStrings(zone, unmangled_segments, final_len);
-#endif  // !defined(DART_PRECOMPILED_RUNTIME)
 
   return Symbols::New(thread, unmangled_name);
 }
 
-RawString* String::ScrubNameRetainPrivate(const String& name) {
+RawString* String::ScrubNameRetainPrivate(const String& name,
+                                          bool is_extension) {
 #if !defined(DART_PRECOMPILED_RUNTIME)
   intptr_t len = name.Length();
   intptr_t start = 0;
   intptr_t at_pos = -1;  // Position of '@' in the name, if any.
   bool is_setter = false;
 
+  String& result = String::Handle();
+
+  // If extension strip out the leading prefix e.g" ext|func would strip out
+  // 'ext|'.
+  if (is_extension) {
+    // First scan till we see the '|' character.
+    for (intptr_t i = 0; i < len; i++) {
+      if (name.CharAt(i) == '|') {
+        result = String::SubString(name, start, (i - start));
+        result = String::Concat(result, Symbols::Dot());
+        start = i + 1;
+        break;
+      } else if (name.CharAt(i) == ':') {
+        if (start != 0) {
+          // Reset and break.
+          start = 0;
+          is_setter = false;
+          break;
+        }
+        if (name.CharAt(0) == 's') {
+          is_setter = true;
+        }
+        start = i + 1;
+      }
+    }
+  }
+
   for (intptr_t i = start; i < len; i++) {
-    if (name.CharAt(i) == ':') {
-      ASSERT(start == 0);  // Only one : is possible in getters or setters.
-      if (name.CharAt(0) == 's') {
+    if (name.CharAt(i) == ':' || (is_extension && name.CharAt(i) == '#')) {
+      // Only one : is possible in getters or setters.
+      ASSERT(is_extension || start == 0);
+      if (name.CharAt(start) == 's') {
         is_setter = true;
       }
       start = i + 1;
@@ -385,8 +461,13 @@
     return name.raw();
   }
 
-  String& result =
-      String::Handle(String::SubString(name, start, (len - start)));
+  if (is_extension) {
+    const String& fname =
+        String::Handle(String::SubString(name, start, (len - start)));
+    result = String::Concat(result, fname);
+  } else {
+    result = String::SubString(name, start, (len - start));
+  }
 
   if (is_setter) {
     // Setters need to end with '='.
@@ -642,8 +723,8 @@
   cls = Class::New<CodeSourceMap>(isolate);
   code_source_map_class_ = cls.raw();
 
-  cls = Class::New<StackMap>(isolate);
-  stackmap_class_ = cls.raw();
+  cls = Class::New<CompressedStackMaps>(isolate);
+  compressed_stackmaps_class_ = cls.raw();
 
   cls = Class::New<LocalVarDescriptors>(isolate);
   var_descriptors_class_ = cls.raw();
@@ -1035,7 +1116,7 @@
   object_pool_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
   pc_descriptors_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
   code_source_map_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
-  stackmap_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+  compressed_stackmaps_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
   var_descriptors_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
   exception_handlers_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
   context_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
@@ -1135,7 +1216,7 @@
   SET_CLASS_NAME(object_pool, ObjectPool);
   SET_CLASS_NAME(code_source_map, CodeSourceMap);
   SET_CLASS_NAME(pc_descriptors, PcDescriptors);
-  SET_CLASS_NAME(stackmap, StackMap);
+  SET_CLASS_NAME(compressed_stackmaps, CompressedStackMaps);
   SET_CLASS_NAME(var_descriptors, LocalVarDescriptors);
   SET_CLASS_NAME(exception_handlers, ExceptionHandlers);
   SET_CLASS_NAME(context, Context);
@@ -1222,12 +1303,12 @@
     ASSERT(size <= map->HeapSize());
     memset(reinterpret_cast<void*>(RawObject::ToAddr(map) + size), 0,
            map->HeapSize() - size);
-  } else if (cid == kStackMapCid) {
-    RawStackMap* map = StackMap::RawCast(object);
-    intptr_t size = StackMap::UnroundedSize(map);
-    ASSERT(size <= map->HeapSize());
-    memset(reinterpret_cast<void*>(RawObject::ToAddr(map) + size), 0,
-           map->HeapSize() - size);
+  } else if (cid == kCompressedStackMapsCid) {
+    RawCompressedStackMaps* maps = CompressedStackMaps::RawCast(object);
+    intptr_t size = CompressedStackMaps::UnroundedSize(maps);
+    ASSERT(size <= maps->HeapSize());
+    memset(reinterpret_cast<void*>(RawObject::ToAddr(maps) + size), 0,
+           maps->HeapSize() - size);
   } else if (cid == kPcDescriptorsCid) {
     RawPcDescriptors* desc = PcDescriptors::RawCast(object);
     intptr_t size = PcDescriptors::UnroundedSize(desc);
@@ -1279,9 +1360,7 @@
         old_tags = tags;
         // We can't use obj.CompareAndSwapTags here because we don't have a
         // handle for the new object.
-        tags = AtomicOperations::CompareAndSwapUint32(&raw->ptr()->tags_,
-                                                      old_tags, new_tags);
-      } while (tags != old_tags);
+      } while (!raw->ptr()->tags_.compare_exchange_weak(old_tags, new_tags));
 
       intptr_t leftover_len = (leftover_size - TypedData::InstanceSize(0));
       ASSERT(TypedData::InstanceSize(leftover_len) == leftover_size);
@@ -1310,9 +1389,7 @@
         old_tags = tags;
         // We can't use obj.CompareAndSwapTags here because we don't have a
         // handle for the new object.
-        tags = AtomicOperations::CompareAndSwapUint32(&raw->ptr()->tags_,
-                                                      old_tags, new_tags);
-      } while (tags != old_tags);
+      } while (!raw->ptr()->tags_.compare_exchange_weak(old_tags, new_tags));
     }
   }
 }
@@ -2333,7 +2410,8 @@
 
 bool Class::IsInFullSnapshot() const {
   NoSafepointScope no_safepoint;
-  return raw_ptr()->library_->ptr()->is_in_fullsnapshot_;
+  return RawLibrary::InFullSnapshotBit::decode(
+      raw_ptr()->library_->ptr()->flags_);
 }
 
 RawAbstractType* Class::RareType() const {
@@ -4008,8 +4086,8 @@
       return Symbols::CodeSourceMap().raw();
     case kPcDescriptorsCid:
       return Symbols::PcDescriptors().raw();
-    case kStackMapCid:
-      return Symbols::StackMap().raw();
+    case kCompressedStackMapsCid:
+      return Symbols::CompressedStackMaps().raw();
     case kLocalVarDescriptorsCid:
       return Symbols::LocalVarDescriptors().raw();
     case kExceptionHandlersCid:
@@ -5477,7 +5555,7 @@
   TypeArguments& result = TypeArguments::Handle();
   result = InstantiateFrom(instantiator_type_arguments, function_type_arguments,
                            kAllFree, NULL, Heap::kOld);
-  // Instantiation did not result in bound error. Canonicalize type arguments.
+  // Canonicalize type arguments.
   result = result.Canonicalize();
   // InstantiateAndCanonicalizeFrom is not reentrant. It cannot have been called
   // indirectly, so the prior_instantiations array cannot have grown.
@@ -6623,6 +6701,15 @@
 }
 
 bool Function::CanBeInlined() const {
+  // Our force-optimized functions cannot deoptimize to an unoptimized frame.
+  // If the instructions of the force-optimized function body get moved via
+  // code motion, we might attempt do deoptimize a frame where the force-
+  // optimized function has only partially finished. Since force-optimized
+  // functions cannot deoptimize to unoptimized frames we prevent them from
+  // being inlined (for now).
+  if (ForceOptimize()) {
+    return FLAG_precompiled_mode;
+  }
 #if defined(PRODUCT)
   return is_inlinable() && !is_external() && !is_generated_body();
 #else
@@ -7883,7 +7970,7 @@
   if (FLAG_show_internal_names) {
     return name();
   }
-  return String::ScrubName(String::Handle(name()));
+  return String::ScrubName(String::Handle(name()), is_extension_member());
 }
 
 RawString* Function::QualifiedName(NameVisibility name_visibility) const {
@@ -8673,7 +8760,7 @@
   if (FLAG_show_internal_names) {
     return name();
   }
-  return String::ScrubName(String::Handle(name()));
+  return String::ScrubName(String::Handle(name()), is_extension_member());
 }
 
 intptr_t Field::guarded_list_length() const {
@@ -11083,7 +11170,9 @@
   result.StorePointer(&result.raw_ptr()->loaded_scripts_, Array::null());
   result.set_native_entry_resolver(NULL);
   result.set_native_entry_symbol_resolver(NULL);
+  result.set_flags(0);
   result.set_is_in_fullsnapshot(false);
+  result.set_is_nnbd(false);
   if (dart_private_scheme) {
     // Never debug dart:_ libraries.
     result.set_debuggable(false);
@@ -11119,6 +11208,10 @@
   return NewLibraryHelper(url, false);
 }
 
+void Library::set_flags(uint8_t flags) const {
+  StoreNonPointer(&raw_ptr()->flags_, flags);
+}
+
 void Library::InitCoreLibrary(Isolate* isolate) {
   Thread* thread = Thread::Current();
   Zone* zone = thread->zone();
@@ -12808,84 +12901,70 @@
   return "CodeSourceMap";
 }
 
-bool StackMap::GetBit(intptr_t bit_index) const {
-  ASSERT(InRange(bit_index));
-  int byte_index = bit_index >> kBitsPerByteLog2;
-  int bit_remainder = bit_index & (kBitsPerByte - 1);
-  uint8_t byte_mask = 1U << bit_remainder;
-  uint8_t byte = raw_ptr()->data()[byte_index];
-  return (byte & byte_mask) != 0;
+intptr_t CompressedStackMaps::Hash() const {
+  uint32_t hash = 0;
+  for (intptr_t i = 0; i < payload_size(); i++) {
+    uint8_t byte = Payload()[i];
+    hash = CombineHashes(hash, byte);
+  }
+  return FinalizeHash(hash, kHashBits);
 }
 
-void StackMap::SetBit(intptr_t bit_index, bool value) const {
-  ASSERT(InRange(bit_index));
-  int byte_index = bit_index >> kBitsPerByteLog2;
-  int bit_remainder = bit_index & (kBitsPerByte - 1);
-  uint8_t byte_mask = 1U << bit_remainder;
-  NoSafepointScope no_safepoint;
-  uint8_t* byte_addr = UnsafeMutableNonPointer(&raw_ptr()->data()[byte_index]);
-  if (value) {
-    *byte_addr |= byte_mask;
-  } else {
-    *byte_addr &= ~byte_mask;
-  }
-}
+RawCompressedStackMaps* CompressedStackMaps::New(
+    const GrowableArray<uint8_t>& payload) {
+  ASSERT(Object::compressed_stackmaps_class() != Class::null());
+  auto& result = CompressedStackMaps::Handle();
 
-RawStackMap* StackMap::New(BitmapBuilder* bmap, intptr_t slow_path_bit_count) {
-  ASSERT(Object::stackmap_class() != Class::null());
-  ASSERT(bmap != NULL);
-  StackMap& result = StackMap::Handle();
-  // Guard against integer overflow of the instance size computation.
-  intptr_t length = bmap->Length();
-  intptr_t payload_size = Utils::RoundUp(length, kBitsPerByte) / kBitsPerByte;
-  if ((length < 0) || (length > kMaxUint16) ||
-      (payload_size > kMaxLengthInBytes)) {
-    // This should be caught before we reach here.
-    FATAL1("Fatal error in StackMap::New: invalid length %" Pd "\n", length);
-  }
-  if ((slow_path_bit_count < 0) || (slow_path_bit_count > kMaxUint16)) {
-    // This should be caught before we reach here.
-    FATAL1("Fatal error in StackMap::New: invalid slow_path_bit_count %" Pd
-           "\n",
-           slow_path_bit_count);
+  const uintptr_t payload_size = payload.length();
+  if (payload_size > kMaxInt32) {
+    FATAL1(
+        "Fatal error in CompressedStackMaps::New: "
+        "invalid payload size %" Pu "\n",
+        payload_size);
   }
   {
-    // StackMap data objects are associated with a code object, allocate them
-    // in old generation.
+    // CompressedStackMaps data objects are associated with a code object,
+    // allocate them in old generation.
     RawObject* raw = Object::Allocate(
-        StackMap::kClassId, StackMap::InstanceSize(length), Heap::kOld);
+        CompressedStackMaps::kClassId,
+        CompressedStackMaps::InstanceSize(payload_size), Heap::kOld);
     NoSafepointScope no_safepoint;
     result ^= raw;
-    result.SetLength(length);
+    result.set_payload_size(payload_size);
   }
-  if (payload_size > 0) {
-    // Ensure leftover bits are deterministic.
-    result.raw()->ptr()->data()[payload_size - 1] = 0;
-  }
-  for (intptr_t i = 0; i < length; ++i) {
-    result.SetBit(i, bmap->Get(i));
-  }
-  result.SetSlowPathBitCount(slow_path_bit_count);
+  result.SetPayload(payload);
+
   return result.raw();
 }
 
-const char* StackMap::ToCString() const {
-  if (IsNull()) return "{null}";
-  // Guard against integer overflow in the computation of alloc_size.
-  //
-  // TODO(kmillikin): We could just truncate the string if someone
-  // tries to print a 2 billion plus entry stackmap.
-  if (Length() > kIntptrMax) {
-    FATAL1("Length() is unexpectedly large (%" Pd ")", Length());
+void CompressedStackMaps::SetPayload(
+    const GrowableArray<uint8_t>& payload) const {
+  auto const 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++) {
+    payload_start[i] = payload.At(i);
   }
-  Thread* thread = Thread::Current();
-  intptr_t alloc_size = Length() + 1;
-  char* chars = thread->zone()->Alloc<char>(alloc_size);
-  for (intptr_t i = 0; i < Length(); i++) {
-    chars[i] = IsObject(i) ? '1' : '0';
+}
+
+const char* CompressedStackMaps::ToCString() const {
+  ZoneTextBuffer b(Thread::Current()->zone(), 100);
+  CompressedStackMapsIterator it(*this);
+  bool first_entry = true;
+  while (it.MoveNext()) {
+    if (first_entry) {
+      first_entry = false;
+    } else {
+      b.AddString("\n");
+    }
+    b.Printf("0x%08x: ", it.pc_offset());
+    for (intptr_t i = 0, n = it.length(); i < n; i++) {
+      b.AddString(it.IsObject(i) ? "1" : "0");
+    }
   }
-  chars[alloc_size - 1] = '\0';
-  return chars;
+  return b.buffer();
 }
 
 RawString* LocalVarDescriptors::GetName(intptr_t var_index) const {
@@ -14449,9 +14528,9 @@
   set_state_bits(AliveBit::update(value, raw_ptr()->state_bits_));
 }
 
-void Code::set_stackmaps(const Array& maps) const {
+void Code::set_compressed_stackmaps(const CompressedStackMaps& maps) const {
   ASSERT(maps.IsOld());
-  StorePointer(&raw_ptr()->stackmaps_, maps.raw());
+  StorePointer(&raw_ptr()->compressed_stackmaps_, maps.raw());
 }
 
 #if !defined(DART_PRECOMPILED_RUNTIME) && !defined(DART_PRECOMPILER)
@@ -15118,39 +15197,6 @@
 #endif
 }
 
-RawStackMap* Code::GetStackMap(uint32_t pc_offset,
-                               Array* maps,
-                               StackMap* map) const {
-  // This code is used during iterating frames during a GC and hence it
-  // should not in turn start a GC.
-  NoSafepointScope no_safepoint;
-  if (stackmaps() == Array::null()) {
-    // No stack maps are present in the code object which means this
-    // frame relies on tagged pointers.
-    return StackMap::null();
-  }
-  // A stack map is present in the code object, use the stack map to visit
-  // frame slots which are marked as having objects.
-  *maps = stackmaps();
-  *map = StackMap::null();
-  for (intptr_t i = 0; i < maps->Length(); i += 2) {
-    // The reinterpret_cast from Smi::RawCast is inlined here because in
-    // debug mode, it creates Handles due to the ASSERT.
-    const uint32_t offset =
-        ValueFromRawSmi(reinterpret_cast<RawSmi*>(maps->At(i)));
-    if (offset != pc_offset) continue;
-    *map ^= maps->At(i + 1);
-    ASSERT(!map->IsNull());
-    return map->raw();
-  }
-  // If we are missing a stack map, this must either be unoptimized code, or
-  // the entry to an osr function. (In which case all stack slots are
-  // considered to have tagged pointers.)
-  // Running with --verify-on-transition should hit this.
-  ASSERT(!is_optimized() || (pc_offset == EntryPoint() - PayloadStart()));
-  return StackMap::null();
-}
-
 void Code::GetInlinedFunctionsAtInstruction(
     intptr_t pc_offset,
     GrowableArray<const Function*>* functions,
@@ -16641,7 +16687,6 @@
       return true;
     }
     AbstractType& instantiated_other = AbstractType::Handle(zone, other.raw());
-    // Note that we may encounter a bound error in checked mode.
     if (!other.IsInstantiated()) {
       instantiated_other = other.InstantiateFrom(
           other_instantiator_type_arguments, other_function_type_arguments,
@@ -16684,7 +16729,6 @@
   Class& other_class = Class::Handle(zone);
   TypeArguments& other_type_arguments = TypeArguments::Handle(zone);
   AbstractType& instantiated_other = AbstractType::Handle(zone, other.raw());
-  // Note that we may encounter a bound error in checked mode.
   if (!other.IsInstantiated()) {
     instantiated_other = other.InstantiateFrom(
         other_instantiator_type_arguments, other_function_type_arguments,
@@ -17373,7 +17417,6 @@
     if (!bound.IsFinalized()) {
       return false;  // TODO(regis): Return "maybe after instantiation".
     }
-    // The current bound_trail cannot be used, because operands are swapped.
     if (bound.IsSubtypeOf(other, space)) {
       return true;
     }
@@ -20820,7 +20863,7 @@
   Object::MakeUnusedSpaceTraversable(array, old_size, new_size);
 
   // Update the size in the header field and length of the array object.
-  uword tags = array.raw_ptr()->tags_;
+  uint32_t tags = array.raw_ptr()->tags_;
   ASSERT(kArrayCid == RawObject::ClassIdTag::decode(tags));
   uint32_t old_tags;
   do {
@@ -21485,7 +21528,6 @@
 }
 
 bool Pointer::IsPointer(const Instance& obj) {
-  ASSERT(!obj.IsNull());
   return RawObject::IsFfiPointerClassId(obj.raw()->GetClassId());
 }
 
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 853f502..1595e42 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -10,8 +10,11 @@
 #endif
 
 #include <tuple>
+
 #include "include/dart_api.h"
 #include "platform/assert.h"
+#include "platform/atomic.h"
+#include "platform/thread_sanitizer.h"
 #include "platform/utils.h"
 #include "vm/bitmap.h"
 #include "vm/code_entry_kind.h"
@@ -270,8 +273,8 @@
   void operator=(RawObject* value) { initializeHandle(this, value); }
 
   uint32_t CompareAndSwapTags(uint32_t old_tags, uint32_t new_tags) const {
-    return AtomicOperations::CompareAndSwapUint32(&raw()->ptr()->tags_,
-                                                  old_tags, new_tags);
+    raw()->ptr()->tags_.compare_exchange_strong(old_tags, new_tags);
+    return old_tags;
   }
   bool IsCanonical() const { return raw()->IsCanonical(); }
   void SetCanonical() const { raw()->SetCanonical(); }
@@ -467,7 +470,9 @@
   static RawClass* object_pool_class() { return object_pool_class_; }
   static RawClass* pc_descriptors_class() { return pc_descriptors_class_; }
   static RawClass* code_source_map_class() { return code_source_map_class_; }
-  static RawClass* stackmap_class() { return stackmap_class_; }
+  static RawClass* compressed_stackmaps_class() {
+    return compressed_stackmaps_class_;
+  }
   static RawClass* var_descriptors_class() { return var_descriptors_class_; }
   static RawClass* exception_handlers_class() {
     return exception_handlers_class_;
@@ -707,7 +712,7 @@
   }
 
   static cpp_vtable handle_vtable_;
-  static cpp_vtable builtin_vtables_[kNumPredefinedCids];
+  static RelaxedAtomic<cpp_vtable> builtin_vtables_[kNumPredefinedCids];
 
   // The static values below are singletons shared between the different
   // isolates. They are all allocated in the non-GC'd Dart::vm_isolate_.
@@ -736,7 +741,8 @@
   static RawClass* object_pool_class_;   // Class of the ObjectPool vm object.
   static RawClass* pc_descriptors_class_;   // Class of PcDescriptors vm object.
   static RawClass* code_source_map_class_;  // Class of CodeSourceMap vm object.
-  static RawClass* stackmap_class_;         // Class of StackMap vm object.
+  static RawClass*
+      compressed_stackmaps_class_;          // Class of CompressedStackMaps.
   static RawClass* var_descriptors_class_;  // Class of LocalVarDescriptors.
   static RawClass* exception_handlers_class_;  // Class of ExceptionHandlers.
   static RawClass* deopt_info_class_;          // Class of DeoptInfo.
@@ -1059,7 +1065,8 @@
 
   static bool IsInFullSnapshot(RawClass* cls) {
     NoSafepointScope no_safepoint;
-    return cls->ptr()->library_->ptr()->is_in_fullsnapshot_;
+    return RawLibrary::InFullSnapshotBit::decode(
+        cls->ptr()->library_->ptr()->flags_);
   }
 
   // Returns true if the type specified by cls and type_arguments is a
@@ -2726,7 +2733,8 @@
     // On DBC we use native calls instead of IR for the view factories (see
     // kernel_to_il.cc)
 #if !defined(TARGET_ARCH_DBC)
-    if (IsTypedDataViewFactory()) {
+    if (IsTypedDataViewFactory() || IsFfiLoad() || IsFfiStore() ||
+        IsFfiFromAddress() || IsFfiGetAddress()) {
       return true;
     }
 #endif
@@ -2883,6 +2891,28 @@
            RawFunction::kFfiTrampoline;
   }
 
+  bool IsFfiLoad() const {
+    const auto kind = MethodRecognizer::RecognizeKind(*this);
+    return MethodRecognizer::kFfiLoadInt8 <= kind &&
+           kind <= MethodRecognizer::kFfiLoadPointer;
+  }
+
+  bool IsFfiStore() const {
+    const auto kind = MethodRecognizer::RecognizeKind(*this);
+    return MethodRecognizer::kFfiStoreInt8 <= kind &&
+           kind <= MethodRecognizer::kFfiStorePointer;
+  }
+
+  bool IsFfiFromAddress() const {
+    const auto kind = MethodRecognizer::RecognizeKind(*this);
+    return kind == MethodRecognizer::kFfiFromAddress;
+  }
+
+  bool IsFfiGetAddress() const {
+    const auto kind = MethodRecognizer::RecognizeKind(*this);
+    return kind == MethodRecognizer::kFfiGetAddress;
+  }
+
   bool IsAsyncFunction() const { return modifier() == RawFunction::kAsync; }
 
   bool IsAsyncClosure() const {
@@ -4187,9 +4217,18 @@
                     native_symbol_resolver);
   }
 
-  bool is_in_fullsnapshot() const { return raw_ptr()->is_in_fullsnapshot_; }
+  bool is_in_fullsnapshot() const {
+    return RawLibrary::InFullSnapshotBit::decode(raw_ptr()->flags_);
+  }
   void set_is_in_fullsnapshot(bool value) const {
-    StoreNonPointer(&raw_ptr()->is_in_fullsnapshot_, value);
+    set_flags(RawLibrary::InFullSnapshotBit::update(value, raw_ptr()->flags_));
+  }
+
+  bool is_nnbd() const {
+    return RawLibrary::NnbdBit::decode(raw_ptr()->flags_);
+  }
+  void set_is_nnbd(bool value) const {
+    set_flags(RawLibrary::NnbdBit::update(value, raw_ptr()->flags_));
   }
 
   RawString* PrivateName(const String& name) const;
@@ -4203,14 +4242,18 @@
   static void RegisterLibraries(Thread* thread,
                                 const GrowableObjectArray& libs);
 
-  bool IsDebuggable() const { return raw_ptr()->debuggable_; }
+  bool IsDebuggable() const {
+    return RawLibrary::DebuggableBit::decode(raw_ptr()->flags_);
+  }
   void set_debuggable(bool value) const {
-    StoreNonPointer(&raw_ptr()->debuggable_, value);
+    set_flags(RawLibrary::DebuggableBit::update(value, raw_ptr()->flags_));
   }
 
-  bool is_dart_scheme() const { return raw_ptr()->is_dart_scheme_; }
+  bool is_dart_scheme() const {
+    return RawLibrary::DartSchemeBit::decode(raw_ptr()->flags_);
+  }
   void set_is_dart_scheme(bool value) const {
-    StoreNonPointer(&raw_ptr()->is_dart_scheme_, value);
+    set_flags(RawLibrary::DartSchemeBit::update(value, raw_ptr()->flags_));
   }
 
   // Includes 'dart:async', 'dart:typed_data', etc.
@@ -4373,6 +4416,7 @@
   void set_url(const String& url) const;
 
   void set_num_imports(intptr_t value) const;
+  void set_flags(uint8_t flags) const;
   bool HasExports() const;
   RawArray* loaded_scripts() const { return raw_ptr()->loaded_scripts_; }
   RawGrowableObjectArray* metadata() const { return raw_ptr()->metadata_; }
@@ -5102,62 +5146,52 @@
   friend class Object;
 };
 
-class StackMap : public Object {
+class CompressedStackMaps : public Object {
  public:
-  bool IsObject(intptr_t index) const {
-    ASSERT(InRange(index));
-    return GetBit(index);
-  }
+  static const intptr_t kHashBits = 30;
 
-  intptr_t Length() const { return raw_ptr()->length_; }
+  intptr_t payload_size() const { return raw_ptr()->payload_size_; }
 
-  intptr_t SlowPathBitCount() const { return raw_ptr()->slow_path_bit_count_; }
-  void SetSlowPathBitCount(intptr_t bit_count) const {
-    ASSERT(bit_count <= kMaxUint16);
-    StoreNonPointer(&raw_ptr()->slow_path_bit_count_, bit_count);
-  }
-
-  bool Equals(const StackMap& other) const {
-    if (Length() != other.Length()) {
-      return false;
-    }
+  bool Equals(const CompressedStackMaps& other) const {
+    if (payload_size() != other.payload_size()) return false;
     NoSafepointScope no_safepoint;
-    return memcmp(raw_ptr(), other.raw_ptr(), InstanceSize(Length())) == 0;
+    return memcmp(raw_ptr(), other.raw_ptr(), InstanceSize(payload_size())) ==
+           0;
   }
+  intptr_t Hash() const;
 
-  static const intptr_t kMaxLengthInBytes = kSmiMax;
-
-  static intptr_t UnroundedSize(RawStackMap* map) {
-    return UnroundedSize(map->ptr()->length_);
+  static intptr_t UnroundedSize(RawCompressedStackMaps* maps) {
+    return UnroundedSize(maps->ptr()->payload_size_);
   }
-  static intptr_t UnroundedSize(intptr_t len) {
-    // The stackmap payload is in an array of bytes.
-    intptr_t payload_size = Utils::RoundUp(len, kBitsPerByte) / kBitsPerByte;
-    return sizeof(RawStackMap) + payload_size;
+  static intptr_t UnroundedSize(intptr_t length) {
+    return sizeof(RawCompressedStackMaps) + length;
   }
   static intptr_t InstanceSize() {
-    ASSERT(sizeof(RawStackMap) == OFFSET_OF_RETURNED_VALUE(RawStackMap, data));
+    ASSERT(sizeof(RawCompressedStackMaps) ==
+           OFFSET_OF_RETURNED_VALUE(RawCompressedStackMaps, data));
     return 0;
   }
   static intptr_t InstanceSize(intptr_t length) {
     return RoundedAllocationSize(UnroundedSize(length));
   }
-  static RawStackMap* New(BitmapBuilder* bmap, intptr_t slow_path_bit_count);
 
  private:
-  void SetLength(intptr_t length) const {
-    ASSERT(length <= kMaxUint16);
-    StoreNonPointer(&raw_ptr()->length_, length);
+  // The encoding logic for CompressedStackMaps entries is in
+  // CompressedStackMapsBuilder, and the decoding logic is in
+  // CompressedStackMapsIterator.
+  static RawCompressedStackMaps* New(const GrowableArray<uint8_t>& bytes);
+
+  void set_payload_size(intptr_t payload_size) const {
+    StoreNonPointer(&raw_ptr()->payload_size_, payload_size);
   }
 
-  bool InRange(intptr_t index) const { return index < Length(); }
+  const uint8_t* Payload() const { return raw_ptr()->data(); }
+  void SetPayload(const GrowableArray<uint8_t>& payload) const;
 
-  bool GetBit(intptr_t bit_index) const;
-  void SetBit(intptr_t bit_index, bool value) const;
-
-  FINAL_HEAP_OBJECT_IMPLEMENTATION(StackMap, Object);
-  friend class BitmapBuilder;
+  FINAL_HEAP_OBJECT_IMPLEMENTATION(CompressedStackMaps, Object);
   friend class Class;
+  friend class CompressedStackMapsBuilder;
+  friend class CompressedStackMapsIterator;
 };
 
 class ExceptionHandlers : public Object {
@@ -5292,9 +5326,6 @@
     return ForceOptimizedBit::decode(raw_ptr()->state_bits_);
   }
   void set_is_force_optimized(bool value) const;
-  static bool IsForceOptimized(RawCode* code) {
-    return Code::ForceOptimizedBit::decode(code->ptr()->state_bits_);
-  }
 
   bool is_alive() const { return AliveBit::decode(raw_ptr()->state_bits_); }
   void set_is_alive(bool value) const;
@@ -5363,11 +5394,11 @@
   void set_catch_entry_moves_maps(const TypedData& maps) const;
 #endif
 
-  RawArray* stackmaps() const { return raw_ptr()->stackmaps_; }
-  void set_stackmaps(const Array& maps) const;
-  RawStackMap* GetStackMap(uint32_t pc_offset,
-                           Array* stackmaps,
-                           StackMap* map) const;
+  RawCompressedStackMaps* compressed_stackmaps() const {
+    return raw_ptr()->compressed_stackmaps_;
+  }
+  void set_compressed_stackmaps(const CompressedStackMaps& maps) const;
+
   enum CallKind {
     kPcRelativeCall = 1,
     kPcRelativeTailCall = 2,
@@ -7800,8 +7831,9 @@
 
   static RawString* RemovePrivateKey(const String& name);
 
-  static RawString* ScrubName(const String& name);
-  static RawString* ScrubNameRetainPrivate(const String& name);
+  static RawString* ScrubName(const String& name, bool is_extension = false);
+  static RawString* ScrubNameRetainPrivate(const String& name,
+                                           bool is_extension = false);
 
   static bool EqualsIgnoringPrivateKey(const String& str1, const String& str2);
 
@@ -9905,7 +9937,8 @@
   return Isolate::Current()->class_table()->At(raw()->GetClassId());
 }
 
-DART_FORCE_INLINE void Object::SetRaw(RawObject* value) {
+DART_FORCE_INLINE
+void Object::SetRaw(RawObject* value) {
   NoSafepointScope no_safepoint_scope;
   raw_ = value;
   if ((reinterpret_cast<uword>(value) & kSmiTagMask) == kSmiTag) {
diff --git a/runtime/vm/object_service.cc b/runtime/vm/object_service.cc
index 1c12894..02c90ac 100644
--- a/runtime/vm/object_service.cc
+++ b/runtime/vm/object_service.cc
@@ -742,7 +742,7 @@
   Object::PrintJSONImpl(stream, ref);
 }
 
-void StackMap::PrintJSONImpl(JSONStream* stream, bool ref) const {
+void CompressedStackMaps::PrintJSONImpl(JSONStream* stream, bool ref) const {
   Object::PrintJSONImpl(stream, ref);
 }
 
diff --git a/runtime/vm/os_thread.cc b/runtime/vm/os_thread.cc
index e3e9ddf..4185a08 100644
--- a/runtime/vm/os_thread.cc
+++ b/runtime/vm/os_thread.cc
@@ -112,13 +112,12 @@
 
 void OSThread::DisableThreadInterrupts() {
   ASSERT(OSThread::Current() == this);
-  AtomicOperations::FetchAndIncrement(&thread_interrupt_disabled_);
+  thread_interrupt_disabled_.fetch_add(1u);
 }
 
 void OSThread::EnableThreadInterrupts() {
   ASSERT(OSThread::Current() == this);
-  uintptr_t old =
-      AtomicOperations::FetchAndDecrement(&thread_interrupt_disabled_);
+  uintptr_t old = thread_interrupt_disabled_.fetch_sub(1u);
   if (FLAG_profiler && (old == 1)) {
     // We just decremented from 1 to 0.
     // Make sure the thread interrupter is awake.
@@ -132,7 +131,7 @@
 }
 
 bool OSThread::ThreadInterruptsEnabled() {
-  return AtomicOperations::LoadRelaxed(&thread_interrupt_disabled_) == 0;
+  return thread_interrupt_disabled_ == 0;
 }
 
 static void DeleteThread(void* thread) {
diff --git a/runtime/vm/os_thread.h b/runtime/vm/os_thread.h
index cd17268..2479dfa 100644
--- a/runtime/vm/os_thread.h
+++ b/runtime/vm/os_thread.h
@@ -6,6 +6,7 @@
 #define RUNTIME_VM_OS_THREAD_H_
 
 #include "platform/address_sanitizer.h"
+#include "platform/atomic.h"
 #include "platform/globals.h"
 #include "platform/safe_stack.h"
 #include "vm/allocation.h"
@@ -295,7 +296,7 @@
   // All |Thread|s are registered in the thread list.
   OSThread* thread_list_next_;
 
-  uintptr_t thread_interrupt_disabled_;
+  RelaxedAtomic<uintptr_t> thread_interrupt_disabled_;
   Log* log_;
   uword stack_base_;
   uword stack_limit_;
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index a8f25d3..4362617 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -226,7 +226,7 @@
 
 intptr_t SampleBuffer::ReserveSampleSlot() {
   ASSERT(samples_ != NULL);
-  uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_);
+  uintptr_t cursor = cursor_.fetch_add(1u);
   // Map back into sample buffer range.
   cursor = cursor % capacity_;
   return cursor;
@@ -276,7 +276,7 @@
     return static_cast<intptr_t>((free_sample_ptr - samples_array_ptr) /
                                  Sample::instance_size());
   } else if (cursor_ < static_cast<uintptr_t>(capacity_ - 1)) {
-    return cursor_++;
+    return cursor_ += 1;
   } else {
     return -1;
   }
@@ -789,14 +789,12 @@
     if (gap >= kMaxStep) {
       // Gap between frame pointer and stack pointer is
       // too large.
-      AtomicOperations::IncrementInt64By(&counters_->incomplete_sample_fp_step,
-                                         1);
+      counters_->incomplete_sample_fp_step.fetch_add(1);
       return;
     }
 
     if (!ValidFramePointer(fp)) {
-      AtomicOperations::IncrementInt64By(
-          &counters_->incomplete_sample_fp_bounds, 1);
+      counters_->incomplete_sample_fp_bounds.fetch_add(1);
       return;
     }
 
@@ -811,23 +809,20 @@
 
       if (fp <= previous_fp) {
         // Frame pointer did not move to a higher address.
-        AtomicOperations::IncrementInt64By(
-            &counters_->incomplete_sample_fp_step, 1);
+        counters_->incomplete_sample_fp_step.fetch_add(1);
         return;
       }
 
       gap = fp - previous_fp;
       if (gap >= kMaxStep) {
         // Frame pointer step is too large.
-        AtomicOperations::IncrementInt64By(
-            &counters_->incomplete_sample_fp_step, 1);
+        counters_->incomplete_sample_fp_step.fetch_add(1);
         return;
       }
 
       if (!ValidFramePointer(fp)) {
         // Frame pointer is outside of isolate stack boundary.
-        AtomicOperations::IncrementInt64By(
-            &counters_->incomplete_sample_fp_bounds, 1);
+        counters_->incomplete_sample_fp_bounds.fetch_add(1);
         return;
       }
 
@@ -838,8 +833,7 @@
         // the pc is so large that adding one to it will cause an
         // overflow it is invalid and it will cause headaches later
         // while we are building the profile.  Discard it.
-        AtomicOperations::IncrementInt64By(&counters_->incomplete_sample_bad_pc,
-                                           1);
+        counters_->incomplete_sample_bad_pc.fetch_add(1);
         return;
       }
 
@@ -945,18 +939,18 @@
 
     if (FLAG_profile_vm) {
       // Always walk the native stack collecting both native and Dart frames.
-      AtomicOperations::IncrementInt64By(&counters->stack_walker_native, 1);
+      counters->stack_walker_native.fetch_add(1);
       native_stack_walker->walk();
     } else if (StubCode::HasBeenInitialized() && exited_dart_code) {
-      AtomicOperations::IncrementInt64By(&counters->stack_walker_dart_exit, 1);
+      counters->stack_walker_dart_exit.fetch_add(1);
       // We have a valid exit frame info, use the Dart stack walker.
       dart_stack_walker->walk();
     } else if (StubCode::HasBeenInitialized() && in_dart_code) {
-      AtomicOperations::IncrementInt64By(&counters->stack_walker_dart, 1);
+      counters->stack_walker_dart.fetch_add(1);
       // We are executing Dart code. We have frame pointers.
       dart_stack_walker->walk();
     } else {
-      AtomicOperations::IncrementInt64By(&counters->stack_walker_none, 1);
+      counters->stack_walker_none.fetch_add(1);
       sample->SetAt(0, pc);
     }
 
@@ -1278,16 +1272,14 @@
   uword stack_lower = 0;
   uword stack_upper = 0;
   if (!InitialRegisterCheck(pc, fp, sp)) {
-    AtomicOperations::IncrementInt64By(
-        &counters_.failure_native_allocation_sample, 1);
+    counters_.failure_native_allocation_sample.fetch_add(1);
     return NULL;
   }
 
   if (!(OSThread::GetCurrentStackBounds(&stack_lower, &stack_upper) &&
         ValidateThreadStackBounds(fp, sp, stack_lower, stack_upper))) {
     // Could not get stack boundary.
-    AtomicOperations::IncrementInt64By(
-        &counters_.failure_native_allocation_sample, 1);
+    counters_.failure_native_allocation_sample.fetch_add(1);
     return NULL;
   }
 
@@ -1349,7 +1341,7 @@
 
   // Thread is not doing VM work.
   if (thread->task_kind() == Thread::kUnknownTask) {
-    AtomicOperations::IncrementInt64By(&counters_.bail_out_unknown_task, 1);
+    counters_.bail_out_unknown_task.fetch_add(1);
     return;
   }
 
@@ -1357,8 +1349,7 @@
     // The JumpToFrame stub manually adjusts the stack pointer, frame
     // pointer, and some isolate state.  It is not safe to walk the
     // stack when executing this stub.
-    AtomicOperations::IncrementInt64By(
-        &counters_.bail_out_jump_to_exception_handler, 1);
+    counters_.bail_out_jump_to_exception_handler.fetch_add(1);
     return;
   }
 
@@ -1392,14 +1383,13 @@
   }
 
   if (!CheckIsolate(isolate)) {
-    AtomicOperations::IncrementInt64By(&counters_.bail_out_check_isolate, 1);
+    counters_.bail_out_check_isolate.fetch_add(1);
     return;
   }
 
   if (thread->IsMutatorThread()) {
     if (isolate->IsDeoptimizing()) {
-      AtomicOperations::IncrementInt64By(
-          &counters_.single_frame_sample_deoptimizing, 1);
+      counters_.single_frame_sample_deoptimizing.fetch_add(1);
       SampleThreadSingleFrame(thread, pc);
       return;
     }
@@ -1411,8 +1401,7 @@
   }
 
   if (!InitialRegisterCheck(pc, fp, sp)) {
-    AtomicOperations::IncrementInt64By(
-        &counters_.single_frame_sample_register_check, 1);
+    counters_.single_frame_sample_register_check.fetch_add(1);
     SampleThreadSingleFrame(thread, pc);
     return;
   }
@@ -1421,8 +1410,7 @@
   uword stack_upper = 0;
   if (!GetAndValidateThreadStackBounds(os_thread, thread, fp, sp, &stack_lower,
                                        &stack_upper)) {
-    AtomicOperations::IncrementInt64By(
-        &counters_.single_frame_sample_get_and_validate_stack_bounds, 1);
+    counters_.single_frame_sample_get_and_validate_stack_bounds.fetch_add(1);
     // Could not get stack boundary.
     SampleThreadSingleFrame(thread, pc);
     return;
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index c972c40..07355ef 100644
--- a/runtime/vm/profiler.h
+++ b/runtime/vm/profiler.h
@@ -47,7 +47,7 @@
   V(failure_native_allocation_sample)
 
 struct ProfilerCounters {
-#define DECLARE_PROFILER_COUNTER(name) ALIGN8 int64_t name;
+#define DECLARE_PROFILER_COUNTER(name) RelaxedAtomic<int64_t> name;
   PROFILER_COUNTERS(DECLARE_PROFILER_COUNTER)
 #undef DECLARE_PROFILER_COUNTER
 };
@@ -677,7 +677,7 @@
   VirtualMemory* memory_;
   Sample* samples_;
   intptr_t capacity_;
-  uintptr_t cursor_;
+  RelaxedAtomic<uintptr_t> cursor_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(SampleBuffer);
diff --git a/runtime/vm/program_visitor.cc b/runtime/vm/program_visitor.cc
index 55d1d56..1b827d7 100644
--- a/runtime/vm/program_visitor.cc
+++ b/runtime/vm/program_visitor.cc
@@ -201,42 +201,39 @@
   }
 }
 
-class StackMapKeyValueTrait {
+class CompressedStackMapsKeyValueTrait {
  public:
   // Typedefs needed for the DirectChainedHashMap template.
-  typedef const StackMap* Key;
-  typedef const StackMap* Value;
-  typedef const StackMap* Pair;
+  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) {
-    intptr_t hash = key->SlowPathBitCount();
-    hash = CombineHashes(hash, key->Length());
-    return FinalizeHash(hash, kBitsPerWord - 1);
-  }
+  static inline intptr_t Hashcode(Key key) { return key->Hash(); }
 
   static inline bool IsKeyEqual(Pair pair, Key key) {
     return pair->Equals(*key);
   }
 };
 
-typedef DirectChainedHashMap<StackMapKeyValueTrait> StackMapSet;
+typedef DirectChainedHashMap<CompressedStackMapsKeyValueTrait>
+    CompressedStackMapsSet;
 
-void ProgramVisitor::DedupStackMaps() {
-  class DedupStackMapsVisitor : public FunctionVisitor {
+void ProgramVisitor::DedupCompressedStackMaps() {
+  class DedupCompressedStackMapsVisitor : public FunctionVisitor {
    public:
-    explicit DedupStackMapsVisitor(Zone* zone)
+    explicit DedupCompressedStackMapsVisitor(Zone* zone)
         : zone_(zone),
-          canonical_stackmaps_(),
+          canonical_compressed_stackmaps_set_(),
           code_(Code::Handle(zone)),
-          stackmaps_(Array::Handle(zone)),
-          stackmap_(StackMap::Handle(zone)) {}
+          compressed_stackmaps_(CompressedStackMaps::Handle(zone)) {}
 
-    void AddStackMap(const StackMap& stackmap) {
-      canonical_stackmaps_.Insert(&StackMap::ZoneHandle(zone_, stackmap.raw()));
+    void AddCompressedStackMaps(const CompressedStackMaps& maps) {
+      canonical_compressed_stackmaps_set_.Insert(
+          &CompressedStackMaps::ZoneHandle(zone_, maps.raw()));
     }
 
     void Visit(const Function& function) {
@@ -244,43 +241,40 @@
         return;
       }
       code_ = function.CurrentCode();
-      stackmaps_ = code_.stackmaps();
-      if (stackmaps_.IsNull()) return;
-      for (intptr_t i = 1; i < stackmaps_.Length(); i += 2) {
-        stackmap_ ^= stackmaps_.At(i);
-        stackmap_ = DedupStackMap(stackmap_);
-        stackmaps_.SetAt(i, stackmap_);
-      }
+      compressed_stackmaps_ = code_.compressed_stackmaps();
+      if (compressed_stackmaps_.IsNull()) return;
+      compressed_stackmaps_ = DedupCompressedStackMaps(compressed_stackmaps_);
+      code_.set_compressed_stackmaps(compressed_stackmaps_);
     }
 
-    RawStackMap* DedupStackMap(const StackMap& stackmap) {
-      const StackMap* canonical_stackmap =
-          canonical_stackmaps_.LookupValue(&stackmap);
-      if (canonical_stackmap == NULL) {
-        AddStackMap(stackmap);
-        return stackmap.raw();
+    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_stackmap->raw();
+        return canonical_maps->raw();
       }
     }
 
    private:
     Zone* zone_;
-    StackMapSet canonical_stackmaps_;
+    CompressedStackMapsSet canonical_compressed_stackmaps_set_;
     Code& code_;
-    Array& stackmaps_;
-    StackMap& stackmap_;
+    CompressedStackMaps& compressed_stackmaps_;
   };
 
-  DedupStackMapsVisitor visitor(Thread::Current()->zone());
+  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.IsStackMap()) {
-        visitor.AddStackMap(StackMap::Cast(object));
+      if (object.IsCompressedStackMaps()) {
+        visitor.AddCompressedStackMaps(CompressedStackMaps::Cast(object));
       }
     }
   }
@@ -620,11 +614,6 @@
     void Visit(const Function& function) {
       code_ = function.CurrentCode();
       if (!code_.IsNull()) {
-        list_ = code_.stackmaps();
-        if (!list_.IsNull()) {
-          list_ = DedupList(list_);
-          code_.set_stackmaps(list_);
-        }
         list_ = code_.inlined_id_to_function();
         if (!list_.IsNull()) {
           list_ = DedupList(list_);
@@ -732,12 +721,17 @@
 
 // Traits for comparing two [Code] objects for equality.
 //
-// It considers two [Code] objects to be equal if
+// The instruction deduplication naturally causes us to have a one-to-many
+// relationship between Instructions and Code objects.
 //
-//   * their [RawInstruction]s are bit-wise equal
-//   * their [RawPcDescriptor]s are the same
-//   * their [RawStackMaps]s are the same
-//   * their static call targets are the same
+// In AOT bare instructions mode frames only have PCs. However, the runtime
+// needs e.g. stack maps from the [Code] to scan such a frame. So we ensure that
+// instructions of code objects are only deduplicated if the metadata in the
+// code is the same. The runtime can then pick any code object corresponding to
+// the PC in the frame and use the metadata.
+//
+// In AOT non-bare instructions mode frames are expanded, like in JIT, and
+// contain the unique code object.
 #if defined(DART_PRECOMPILER)
 class CodeKeyValueTrait {
  public:
@@ -760,13 +754,16 @@
     if (pair->static_calls_target_table() != key->static_calls_target_table()) {
       return false;
     }
-    if (pair->pc_descriptors() == key->pc_descriptors()) {
+    if (pair->pc_descriptors() != key->pc_descriptors()) {
       return false;
     }
-    if (pair->stackmaps() == key->stackmaps()) {
+    if (pair->compressed_stackmaps() != key->compressed_stackmaps()) {
       return false;
     }
-    if (pair->catch_entry_moves_maps() == key->catch_entry_moves_maps()) {
+    if (pair->catch_entry_moves_maps() != key->catch_entry_moves_maps()) {
+      return false;
+    }
+    if (pair->exception_handlers() != key->exception_handlers()) {
       return false;
     }
     return Instructions::Equals(pair->instructions(), key->instructions());
@@ -841,7 +838,6 @@
         : zone_(zone),
           canonical_set_(),
           code_(Code::Handle(zone)),
-          owner_(Object::Handle(zone)),
           instructions_(Instructions::Handle(zone)) {}
 
     void VisitObject(RawObject* obj) {
@@ -855,19 +851,25 @@
         return;
       }
       code_ = function.CurrentCode();
-      instructions_ = DedupOneInstructions(code_);
+      instructions_ = DedupOneInstructions(function, code_);
       code_.SetActiveInstructions(instructions_);
       code_.set_instructions(instructions_);
       function.SetInstructions(code_);  // Update cached entry point.
     }
 
-    RawInstructions* DedupOneInstructions(const Code& code) {
+    RawInstructions* DedupOneInstructions(const Function& function,
+                                          const Code& code) {
+      // Switchable calls rely on a unique PC -> Code mapping atm, so we do not
+      // dedup any instructions for instance methods.
+      if (function.IsDynamicFunction()) {
+        return code.instructions();
+      }
+
       const Code* canonical = canonical_set_.LookupValue(&code);
-      if (canonical == NULL) {
+      if (canonical == nullptr) {
         canonical_set_.Insert(&Code::ZoneHandle(zone_, code.raw()));
         return code.instructions();
       } else {
-        owner_ = code.owner();
         return canonical->instructions();
       }
     }
@@ -876,7 +878,6 @@
     Zone* zone_;
     CodeSet canonical_set_;
     Code& code_;
-    Object& owner_;
     Instructions& instructions_;
   };
 
@@ -894,7 +895,7 @@
 
   BindStaticCalls();
   ShareMegamorphicBuckets();
-  DedupStackMaps();
+  DedupCompressedStackMaps();
   DedupPcDescriptors();
   NOT_IN_PRECOMPILED(DedupDeoptEntries());
 #if defined(DART_PRECOMPILER)
diff --git a/runtime/vm/program_visitor.h b/runtime/vm/program_visitor.h
index 3ba3539..d18b60d 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 DedupStackMaps();
+  static void DedupCompressedStackMaps();
   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 209363f..624b55b 100644
--- a/runtime/vm/raw_object.cc
+++ b/runtime/vm/raw_object.cc
@@ -176,10 +176,11 @@
       instance_size = CodeSourceMap::InstanceSize(length);
       break;
     }
-    case kStackMapCid: {
-      const RawStackMap* map = reinterpret_cast<const RawStackMap*>(this);
-      intptr_t length = map->ptr()->length_;
-      instance_size = StackMap::InstanceSize(length);
+    case kCompressedStackMapsCid: {
+      const RawCompressedStackMaps* maps =
+          reinterpret_cast<const RawCompressedStackMaps*>(this);
+      intptr_t length = maps->ptr()->payload_size_;
+      instance_size = CompressedStackMaps::InstanceSize(length);
       break;
     }
     case kLocalVarDescriptorsCid: {
@@ -227,7 +228,7 @@
       if (!class_table->IsValidIndex(class_id) ||
           (!class_table->HasValidClassAt(class_id) && !use_saved_class_table)) {
         FATAL3("Invalid cid: %" Pd ", obj: %p, tags: %x. Corrupt heap?",
-               class_id, this, ptr()->tags_);
+               class_id, this, ptr()->tags_.load());
       }
 #endif  // DEBUG
       instance_size = isolate->GetClassSizeForHeapWalkAt(class_id);
@@ -344,7 +345,7 @@
       break;
     default:
       FATAL3("Invalid cid: %" Pd ", obj: %p, tags: %x. Corrupt heap?", class_id,
-             this, ptr()->tags_);
+             this, ptr()->tags_.load());
       break;
   }
 
@@ -531,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(StackMap, raw_obj->ptr()->length_)
+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 a3a0594..c624330 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -267,8 +267,7 @@
   void SetMarkBitUnsynchronized() {
     ASSERT(IsOldObject());
     ASSERT(!IsMarked());
-    uint32_t tags = ptr()->tags_;
-    ptr()->tags_ = OldAndNotMarkedBit::update(false, tags);
+    ptr()->tags_ = OldAndNotMarkedBit::update(false, ptr()->tags_);
   }
   void ClearMarkBit() {
     ASSERT(IsOldObject());
@@ -318,8 +317,7 @@
   void SetCardRememberedBitUnsynchronized() {
     ASSERT(!IsRemembered());
     ASSERT(!IsCardRemembered());
-    uint32_t tags = ptr()->tags_;
-    ptr()->tags_ = CardRememberedBit::update(true, tags);
+    ptr()->tags_ = CardRememberedBit::update(true, ptr()->tags_);
   }
 
 #define DEFINE_IS_CID(clazz)                                                   \
@@ -360,10 +358,7 @@
     return IsFreeListElement() || IsForwardingCorpse();
   }
 
-  intptr_t GetClassId() const {
-    uint32_t tags = ptr()->tags_;
-    return ClassIdTag::decode(tags);
-  }
+  intptr_t GetClassId() const { return ClassIdTag::decode(ptr()->tags_); }
   intptr_t GetClassIdMayBeSmi() const {
     return IsHeapObject() ? GetClassId() : static_cast<intptr_t>(kSmiCid);
   }
@@ -381,7 +376,7 @@
       // recomputing size from tags.
       const intptr_t size_from_class = HeapSizeFromClass();
       if ((result > size_from_class) && (GetClassId() == kArrayCid) &&
-          (ptr()->tags_ != tags)) {
+          (ptr()->tags_) != tags) {
         result = SizeTag::decode(ptr()->tags_);
       }
       ASSERT(result == size_from_class);
@@ -492,7 +487,7 @@
   static intptr_t NumberOfTypedDataClasses();
 
  private:
-  uint32_t tags_;  // Various object tags (bits).
+  RelaxedAtomic<uint32_t> tags_;  // Various object tags (bits).
 #if defined(HASH_IN_OBJECT_HEADER)
   // On 64 bit there is a hash field in the header for the identity hash.
   uint32_t hash_;
@@ -515,31 +510,28 @@
   intptr_t HeapSizeFromClass() const;
 
   void SetClassId(intptr_t new_cid) {
-    uint32_t tags = ptr()->tags_;
-    ptr()->tags_ = ClassIdTag::update(new_cid, tags);
+    ptr()->tags_ = ClassIdTag::update(new_cid, ptr()->tags_);
   }
 
   template <class TagBitField>
   void UpdateTagBit(bool value) {
     if (value) {
-      AtomicOperations::FetchOrRelaxedUint32(&ptr()->tags_,
-                                             TagBitField::encode(true));
+      ptr()->tags_.fetch_or(TagBitField::encode(true));
     } else {
-      AtomicOperations::FetchAndRelaxedUint32(&ptr()->tags_,
-                                              ~TagBitField::encode(true));
+      ptr()->tags_.fetch_and(~TagBitField::encode(true));
     }
   }
 
   template <class TagBitField>
   bool TryAcquireTagBit() {
-    uint32_t old_tags = AtomicOperations::FetchOrRelaxedUint32(
-        &ptr()->tags_, TagBitField::encode(true));
+    uint32_t mask = TagBitField::encode(true);
+    uint32_t old_tags = ptr()->tags_.fetch_or(mask);
     return !TagBitField::decode(old_tags);
   }
   template <class TagBitField>
   bool TryClearTagBit() {
-    uint32_t old_tags = AtomicOperations::FetchAndRelaxedUint32(
-        &ptr()->tags_, ~TagBitField::encode(true));
+    uint32_t mask = ~TagBitField::encode(true);
+    uint32_t old_tags = ptr()->tags_.fetch_and(mask);
     return TagBitField::decode(old_tags);
   }
 
@@ -1221,6 +1213,20 @@
     kLoaded,          // Library is loaded.
   };
 
+  enum LibraryFlags {
+    kDartSchemeBit = 0,
+    kDebuggableBit,      // True if debugger can stop in library.
+    kInFullSnapshotBit,  // True if library is in a full snapshot.
+    kNnbdBit,            // True if library is non nullable by default.
+    kNumFlagBits,
+  };
+  COMPILE_ASSERT(kNumFlagBits <= (sizeof(uint8_t) * kBitsPerByte));
+  class DartSchemeBit : public BitField<uint8_t, bool, kDartSchemeBit, 1> {};
+  class DebuggableBit : public BitField<uint8_t, bool, kDebuggableBit, 1> {};
+  class InFullSnapshotBit
+      : public BitField<uint8_t, bool, kInFullSnapshotBit, 1> {};
+  class NnbdBit : public BitField<uint8_t, bool, kNnbdBit, 1> {};
+
   RAW_HEAP_OBJECT_IMPLEMENTATION(Library);
 
   VISIT_FROM(RawObject*, name_);
@@ -1259,9 +1265,7 @@
   classid_t index_;       // Library id number.
   uint16_t num_imports_;  // Number of entries in imports_.
   int8_t load_state_;     // Of type LibraryState.
-  bool is_dart_scheme_;
-  bool debuggable_;          // True if debugger can stop in library.
-  bool is_in_fullsnapshot_;  // True if library is in a full snapshot.
+  uint8_t flags_;         // BitField for LibraryFlags.
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
   typedef BitField<uint32_t, bool, 0, 1> IsDeclaredInBytecode;
@@ -1367,9 +1371,7 @@
     RawTypedData* catch_entry_moves_maps_;
     RawSmi* variables_;
   } catch_entry_;
-  // The stackmaps_ array contains alternating Smi and StackMap values, where
-  // each Smi value is the PC offset for the following StackMap value.
-  RawArray* stackmaps_;
+  RawCompressedStackMaps* compressed_stackmaps_;
   RawArray* inlined_id_to_function_;
   RawCodeSourceMap* code_source_map_;
   NOT_IN_PRECOMPILED(RawInstructions* active_instructions_);
@@ -1612,21 +1614,35 @@
   friend class ImageWriter;
 };
 
-// StackMap is an immutable representation of the layout of the stack at a
-// PC. The stack map representation consists of a bit map which marks each
-// live object index starting from the base of the frame.
-//
-// The bit map representation is optimized for dense and small bit maps, without
-// any upper bound.
-class RawStackMap : public RawObject {
-  RAW_HEAP_OBJECT_IMPLEMENTATION(StackMap);
+// RawCompressedStackMaps is a compressed representation of the stack maps
+// for certain PC offsets into a set of instructions, where a stack map is a bit
+// map that marks each live object index starting from the base of the frame.
+class RawCompressedStackMaps : public RawObject {
+  RAW_HEAP_OBJECT_IMPLEMENTATION(CompressedStackMaps);
   VISIT_NOTHING();
 
-  uint16_t length_;               // Length of payload, in bits.
-  uint16_t slow_path_bit_count_;  // Slow path live values, included in length_.
-  // ARM64 requires register_bit_count_ to be as large as 96.
+  uint32_t payload_size_;  // Length of the encoded payload, in bytes.
 
-  // Variable length data follows here (bitmap of the stack layout).
+  // Variable length data follows here. The payload consists of entries with
+  // the following information:
+  //
+  // * 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.
+  //
+  // 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); }
 
@@ -2788,7 +2804,7 @@
          RawObject::IsTypedDataClassId(index) || (index == kContextCid) ||
          (index == kTypeArgumentsCid) || (index == kInstructionsCid) ||
          (index == kObjectPoolCid) || (index == kPcDescriptorsCid) ||
-         (index == kCodeSourceMapCid) || (index == kStackMapCid) ||
+         (index == kCodeSourceMapCid) || (index == kCompressedStackMapsCid) ||
          (index == kLocalVarDescriptorsCid) ||
          (index == kExceptionHandlersCid) || (index == kCodeCid) ||
          (index == kContextScopeCid) || (index == kInstanceCid) ||
diff --git a/runtime/vm/raw_object_fields.cc b/runtime/vm/raw_object_fields.cc
index 3dc239b..c818091 100644
--- a/runtime/vm/raw_object_fields.cc
+++ b/runtime/vm/raw_object_fields.cc
@@ -99,7 +99,7 @@
   F(Code, owner_)                                                              \
   F(Code, exception_handlers_)                                                 \
   F(Code, pc_descriptors_)                                                     \
-  F(Code, stackmaps_)                                                          \
+  F(Code, compressed_stackmaps_)                                               \
   F(Code, inlined_id_to_function_)                                             \
   F(Code, code_source_map_)                                                    \
   F(Bytecode, object_pool_)                                                    \
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index 6773141..56e29f1 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -516,6 +516,7 @@
 MESSAGE_SNAPSHOT_UNREACHABLE(ClosureData);
 MESSAGE_SNAPSHOT_UNREACHABLE(Code);
 MESSAGE_SNAPSHOT_UNREACHABLE(CodeSourceMap);
+MESSAGE_SNAPSHOT_UNREACHABLE(CompressedStackMaps);
 MESSAGE_SNAPSHOT_UNREACHABLE(Error);
 MESSAGE_SNAPSHOT_UNREACHABLE(ExceptionHandlers);
 MESSAGE_SNAPSHOT_UNREACHABLE(FfiTrampolineData);
@@ -537,7 +538,6 @@
 MESSAGE_SNAPSHOT_UNREACHABLE(Script);
 MESSAGE_SNAPSHOT_UNREACHABLE(SignatureData);
 MESSAGE_SNAPSHOT_UNREACHABLE(SingleTargetCache);
-MESSAGE_SNAPSHOT_UNREACHABLE(StackMap);
 MESSAGE_SNAPSHOT_UNREACHABLE(String);
 MESSAGE_SNAPSHOT_UNREACHABLE(SubtypeTestCache);
 MESSAGE_SNAPSHOT_UNREACHABLE(TypedDataBase);
diff --git a/runtime/vm/regexp_assembler_ir.cc b/runtime/vm/regexp_assembler_ir.cc
index 65d81e2..f45a199 100644
--- a/runtime/vm/regexp_assembler_ir.cc
+++ b/runtime/vm/regexp_assembler_ir.cc
@@ -289,7 +289,7 @@
       TypedData::New(kTypedDataInt32ArrayCid, registers_count_, Heap::kOld);
 }
 
-#if defined(TARGET_ARCH_ARM64) || defined(TARGET_ARCH_ARM)
+#if defined(TARGET_ARCH_ARM)
 // Disabling unaligned accesses forces the regexp engine to load characters one
 // by one instead of up to 4 at once, along with the associated performance hit.
 // TODO(zerny): Be less conservative about disabling unaligned accesses.
diff --git a/runtime/vm/runtime_entry.cc b/runtime/vm/runtime_entry.cc
index 4a5d757..9fd4ab7 100644
--- a/runtime/vm/runtime_entry.cc
+++ b/runtime/vm/runtime_entry.cc
@@ -719,7 +719,8 @@
 }
 
 // Check that the given instance is an instance of the given type.
-// Tested instance may not be null, because the null test is inlined.
+// Tested instance may be null, because a null test cannot always be inlined,
+// e.g 'null is T' yields true if T = Null, but false if T = bool.
 // Arg0: instance being checked.
 // Arg1: type.
 // Arg2: type arguments of the instantiator of the type.
@@ -751,6 +752,7 @@
 
 // Check that the type of the given instance is a subtype of the given type and
 // can therefore be assigned.
+// Tested instance may not be null, because a null test is always inlined.
 // Arg0: instance being assigned.
 // Arg1: type being assigned to.
 // Arg2: type arguments of the instantiator of the type being assigned to.
@@ -1565,6 +1567,14 @@
     ic_data.AddReceiverCheck(receiver.GetClassId(), target_function);
   }
 
+  // If the target function has optional parameters or is generic, it's
+  // prologue requires ARGS_DESC_REG to be populated. Yet the switchable calls
+  // do not populate that on the call site, which is why we don't transition
+  // those call sites to monomorphic, but rather directly to call via stub
+  // (which will populate the ARGS_DESC_REG from the ICData).
+  //
+  // Because of this we also don't generate monomorphic checks for those
+  // functions.
   if (!target_function.IsNull() && !target_function.HasOptionalParameters() &&
       !target_function.IsGeneric()) {
     // Patch to monomorphic call.
@@ -3067,6 +3077,12 @@
   ASSERT(Function::HasBytecode(function));
   ASSERT(interpreter != NULL);
 #endif
+  // Tell MemorySanitizer 'argv' is initialized by generated code.
+  if (argc < 0) {
+    MSAN_UNPOISON(argv - argc, -argc * sizeof(RawObject*));
+  } else {
+    MSAN_UNPOISON(argv, argc * sizeof(RawObject*));
+  }
   RawObject* result = interpreter->Call(function, argdesc, argc, argv, thread);
   DEBUG_ASSERT(thread->top_exit_frame_info() == exit_fp);
   if (RawObject::IsErrorClassId(result->GetClassIdMayBeSmi())) {
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index ea0a4a4..1b514fe 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -2856,96 +2856,6 @@
   }
 }
 
-static float arm_reciprocal_sqrt_estimate(float a) {
-  // From the ARM Architecture Reference Manual A2-87.
-  if (isinf(a) || (fabs(a) >= exp2f(126)))
-    return 0.0;
-  else if (a == 0.0)
-    return kPosInfinity;
-  else if (isnan(a))
-    return a;
-
-  uint32_t a_bits = bit_cast<uint32_t, float>(a);
-  uint64_t scaled;
-  if (((a_bits >> 23) & 1) != 0) {
-    // scaled = '0 01111111101' : operand<22:0> : Zeros(29)
-    scaled = (static_cast<uint64_t>(0x3fd) << 52) |
-             ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
-  } else {
-    // scaled = '0 01111111110' : operand<22:0> : Zeros(29)
-    scaled = (static_cast<uint64_t>(0x3fe) << 52) |
-             ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
-  }
-  // result_exp = (380 - UInt(operand<30:23>) DIV 2;
-  int32_t result_exp = (380 - ((a_bits >> 23) & 0xff)) / 2;
-
-  double scaled_d = bit_cast<double, uint64_t>(scaled);
-  ASSERT((scaled_d >= 0.25) && (scaled_d < 1.0));
-
-  double r;
-  if (scaled_d < 0.5) {
-    // range 0.25 <= a < 0.5
-
-    // a in units of 1/512 rounded down.
-    int32_t q0 = static_cast<int32_t>(scaled_d * 512.0);
-    // reciprocal root r.
-    r = 1.0 / sqrt((static_cast<double>(q0) + 0.5) / 512.0);
-  } else {
-    // range 0.5 <= a < 1.0
-
-    // a in units of 1/256 rounded down.
-    int32_t q1 = static_cast<int32_t>(scaled_d * 256.0);
-    // reciprocal root r.
-    r = 1.0 / sqrt((static_cast<double>(q1) + 0.5) / 256.0);
-  }
-  // r in units of 1/256 rounded to nearest.
-  int32_t s = static_cast<int>(256.0 * r + 0.5);
-  double estimate = static_cast<double>(s) / 256.0;
-  ASSERT((estimate >= 1.0) && (estimate <= (511.0 / 256.0)));
-
-  // result = 0 : result_exp<7:0> : estimate<51:29>
-  int32_t result_bits =
-      ((result_exp & 0xff) << 23) |
-      ((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff);
-  return bit_cast<float, int32_t>(result_bits);
-}
-
-static float arm_recip_estimate(float a) {
-  // From the ARM Architecture Reference Manual A2-85.
-  if (isinf(a) || (fabs(a) >= exp2f(126)))
-    return 0.0;
-  else if (a == 0.0)
-    return kPosInfinity;
-  else if (isnan(a))
-    return a;
-
-  uint32_t a_bits = bit_cast<uint32_t, float>(a);
-  // scaled = '0011 1111 1110' : a<22:0> : Zeros(29)
-  uint64_t scaled = (static_cast<uint64_t>(0x3fe) << 52) |
-                    ((static_cast<uint64_t>(a_bits) & 0x7fffff) << 29);
-  // result_exp = 253 - UInt(a<30:23>)
-  int32_t result_exp = 253 - ((a_bits >> 23) & 0xff);
-  ASSERT((result_exp >= 1) && (result_exp <= 252));
-
-  double scaled_d = bit_cast<double, uint64_t>(scaled);
-  ASSERT((scaled_d >= 0.5) && (scaled_d < 1.0));
-
-  // a in units of 1/512 rounded down.
-  int32_t q = static_cast<int32_t>(scaled_d * 512.0);
-  // reciprocal r.
-  double r = 1.0 / ((static_cast<double>(q) + 0.5) / 512.0);
-  // r in units of 1/256 rounded to nearest.
-  int32_t s = static_cast<int32_t>(256.0 * r + 0.5);
-  double estimate = static_cast<double>(s) / 256.0;
-  ASSERT((estimate >= 1.0) && (estimate <= (511.0 / 256.0)));
-
-  // result = sign : result_exp<7:0> : estimate<51:29>
-  int32_t result_bits =
-      (a_bits & 0x80000000) | ((result_exp & 0xff) << 23) |
-      ((bit_cast<uint64_t, double>(estimate) >> 29) & 0x7fffff);
-  return bit_cast<float, int32_t>(result_bits);
-}
-
 static void simd_value_swap(simd_value_t* s1,
                             int i1,
                             simd_value_t* s2,
@@ -3210,26 +3120,26 @@
                (instr->Bits(16, 4) == 11)) {
       // Format(instr, "vrecpeq 'qd, 'qm");
       for (int i = 0; i < 4; i++) {
-        s8d.data_[i].f = arm_recip_estimate(s8m.data_[i].f);
+        s8d.data_[i].f = ReciprocalEstimate(s8m.data_[i].f);
       }
     } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 1) &&
                (instr->Bits(20, 2) == 0) && (instr->Bits(23, 2) == 0)) {
       // Format(instr, "vrecpsq 'qd, 'qn, 'qm");
       for (int i = 0; i < 4; i++) {
-        s8d.data_[i].f = 2.0 - (s8n.data_[i].f * s8m.data_[i].f);
+        s8d.data_[i].f = ReciprocalStep(s8n.data_[i].f, s8m.data_[i].f);
       }
     } else if ((instr->Bits(8, 4) == 5) && (instr->Bit(4) == 0) &&
                (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
                (instr->Bit(7) == 1) && (instr->Bits(16, 4) == 11)) {
       // Format(instr, "vrsqrteqs 'qd, 'qm");
       for (int i = 0; i < 4; i++) {
-        s8d.data_[i].f = arm_reciprocal_sqrt_estimate(s8m.data_[i].f);
+        s8d.data_[i].f = ReciprocalSqrtEstimate(s8m.data_[i].f);
       }
     } else if ((instr->Bits(8, 4) == 15) && (instr->Bit(4) == 1) &&
                (instr->Bits(20, 2) == 2) && (instr->Bits(23, 2) == 0)) {
       // Format(instr, "vrsqrtsqs 'qd, 'qn, 'qm");
       for (int i = 0; i < 4; i++) {
-        s8d.data_[i].f = (3.0 - s8n.data_[i].f * s8m.data_[i].f) / 2.0;
+        s8d.data_[i].f = ReciprocalSqrtStep(s8n.data_[i].f, s8m.data_[i].f);
       }
     } else if ((instr->Bits(8, 4) == 12) && (instr->Bit(4) == 0) &&
                (instr->Bits(20, 2) == 3) && (instr->Bits(23, 2) == 3) &&
diff --git a/runtime/vm/simulator_arm64.cc b/runtime/vm/simulator_arm64.cc
index efc5e89..235a296 100644
--- a/runtime/vm/simulator_arm64.cc
+++ b/runtime/vm/simulator_arm64.cc
@@ -31,6 +31,11 @@
             ULLONG_MAX,
             "Instruction address or instruction count to stop simulator at.");
 
+DEFINE_FLAG(bool,
+            sim_allow_unaligned_accesses,
+            true,
+            "Allow unaligned accesses to Normal memory.");
+
 // This macro provides a platform independent use of sscanf. The reason for
 // SScanF not being implemented in a platform independent way through
 // OS in the same way as SNPrint is that the Windows C Run-Time
@@ -999,9 +1004,10 @@
   FATAL("Cannot continue execution after illegal memory access.");
 }
 
-// The ARMv8 manual advises that an unaligned access may generate a fault,
-// and if not, will likely take a number of additional cycles to execute,
-// so let's just not generate any.
+// ARMv8 supports unaligned memory accesses to normal memory without trapping
+// for all instructions except Load-Exclusive/Store-Exclusive and
+// Load-Acquire/Store-Release.
+// See B2.4.2 "Alignment of data accesses" for more information.
 void Simulator::UnalignedAccess(const char* msg, uword addr, Instr* instr) {
   char buffer[128];
   snprintf(buffer, sizeof(buffer), "unaligned %s at 0x%" Px ", pc=%p\n", msg,
@@ -1027,8 +1033,12 @@
   return icount_ > FLAG_trace_sim_after;
 }
 
-intptr_t Simulator::ReadX(uword addr, Instr* instr) {
-  if ((addr & 7) == 0) {
+intptr_t Simulator::ReadX(uword addr,
+                          Instr* instr,
+                          bool must_be_aligned /* = false */) {
+  const bool allow_unaligned_access =
+      FLAG_sim_allow_unaligned_accesses && !must_be_aligned;
+  if (allow_unaligned_access || (addr & 7) == 0) {
     intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
     return *ptr;
   }
@@ -1037,7 +1047,7 @@
 }
 
 void Simulator::WriteX(uword addr, intptr_t value, Instr* instr) {
-  if ((addr & 7) == 0) {
+  if (FLAG_sim_allow_unaligned_accesses || (addr & 7) == 0) {
     intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
     *ptr = value;
     return;
@@ -1045,8 +1055,12 @@
   UnalignedAccess("write", addr, instr);
 }
 
-uint32_t Simulator::ReadWU(uword addr, Instr* instr) {
-  if ((addr & 3) == 0) {
+uint32_t Simulator::ReadWU(uword addr,
+                           Instr* instr,
+                           bool must_be_aligned /* = false */) {
+  const bool allow_unaligned_access =
+      FLAG_sim_allow_unaligned_accesses && !must_be_aligned;
+  if (allow_unaligned_access || (addr & 3) == 0) {
     uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
     return *ptr;
   }
@@ -1055,7 +1069,7 @@
 }
 
 int32_t Simulator::ReadW(uword addr, Instr* instr) {
-  if ((addr & 3) == 0) {
+  if (FLAG_sim_allow_unaligned_accesses || (addr & 3) == 0) {
     int32_t* ptr = reinterpret_cast<int32_t*>(addr);
     return *ptr;
   }
@@ -1064,7 +1078,7 @@
 }
 
 void Simulator::WriteW(uword addr, uint32_t value, Instr* instr) {
-  if ((addr & 3) == 0) {
+  if (FLAG_sim_allow_unaligned_accesses || (addr & 3) == 0) {
     uint32_t* ptr = reinterpret_cast<uint32_t*>(addr);
     *ptr = value;
     return;
@@ -1073,7 +1087,7 @@
 }
 
 uint16_t Simulator::ReadHU(uword addr, Instr* instr) {
-  if ((addr & 1) == 0) {
+  if (FLAG_sim_allow_unaligned_accesses || (addr & 1) == 0) {
     uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
     return *ptr;
   }
@@ -1082,7 +1096,7 @@
 }
 
 int16_t Simulator::ReadH(uword addr, Instr* instr) {
-  if ((addr & 1) == 0) {
+  if (FLAG_sim_allow_unaligned_accesses || (addr & 1) == 0) {
     int16_t* ptr = reinterpret_cast<int16_t*>(addr);
     return *ptr;
   }
@@ -1091,7 +1105,7 @@
 }
 
 void Simulator::WriteH(uword addr, uint16_t value, Instr* instr) {
-  if ((addr & 1) == 0) {
+  if (FLAG_sim_allow_unaligned_accesses || (addr & 1) == 0) {
     uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
     *ptr = value;
     return;
@@ -1121,13 +1135,13 @@
 
 intptr_t Simulator::ReadExclusiveX(uword addr, Instr* instr) {
   exclusive_access_addr_ = addr;
-  exclusive_access_value_ = ReadX(addr, instr);
+  exclusive_access_value_ = ReadX(addr, instr, /*must_be_aligned=*/true);
   return exclusive_access_value_;
 }
 
 intptr_t Simulator::ReadExclusiveW(uword addr, Instr* instr) {
   exclusive_access_addr_ = addr;
-  exclusive_access_value_ = ReadWU(addr, instr);
+  exclusive_access_value_ = ReadWU(addr, instr, /*must_be_aligned=*/true);
   return exclusive_access_value_;
 }
 
diff --git a/runtime/vm/simulator_arm64.h b/runtime/vm/simulator_arm64.h
index 8a48451..6663e32 100644
--- a/runtime/vm/simulator_arm64.h
+++ b/runtime/vm/simulator_arm64.h
@@ -170,11 +170,13 @@
   inline int16_t ReadH(uword addr, Instr* instr);
   inline void WriteH(uword addr, uint16_t value, Instr* instr);
 
-  inline uint32_t ReadWU(uword addr, Instr* instr);
+  inline uint32_t ReadWU(uword addr,
+                         Instr* instr,
+                         bool must_be_aligned = false);
   inline int32_t ReadW(uword addr, Instr* instr);
   inline void WriteW(uword addr, uint32_t value, Instr* instr);
 
-  inline intptr_t ReadX(uword addr, Instr* instr);
+  inline intptr_t ReadX(uword addr, Instr* instr, bool must_be_aligned = false);
   inline void WriteX(uword addr, intptr_t value, Instr* instr);
 
   // Synchronization primitives support.
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 1f7beaa..61b90a9 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -50,6 +50,7 @@
 class RawClosure;
 class RawClosureData;
 class RawCodeSourceMap;
+class RawCompressedStackMaps;
 class RawContext;
 class RawContextScope;
 class RawDouble;
@@ -85,7 +86,6 @@
 class RawSignatureData;
 class RawSendPort;
 class RawSmi;
-class RawStackMap;
 class RawStackTrace;
 class RawSubtypeTestCache;
 class RawTwoByteString;
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index e05f475..aeef453 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -357,7 +357,7 @@
   Capability& obj = Capability::Handle();
   obj ^= reader.ReadObject();
 
-  EXPECT_STREQ(12345, obj.Id());
+  EXPECT_STREQ("12345", obj.Id());
 
   // Read object back from the snapshot into a C structure.
   ApiNativeScope scope;
@@ -1447,7 +1447,7 @@
       EXPECT_STREQ("A", element->value.as_string);
       element = root->value.as_array.values[1];
       EXPECT_EQ(Dart_CObject_kDouble, element->type);
-      EXPECT_STREQ(2.72, element->value.as_double);
+      EXPECT_STREQ("2.72", element->value.as_double);
       for (int i = 2; i < kArrayLength; i++) {
         element = root->value.as_array.values[i];
         if ((i % 2) == 0) {
@@ -1458,7 +1458,7 @@
           // Double values are expected to not be canonicalized in messages.
           EXPECT_NE(root->value.as_array.values[1], element);
           EXPECT_EQ(Dart_CObject_kDouble, element->type);
-          EXPECT_STREQ(2.72, element->value.as_double);
+          EXPECT_STREQ("2.72", element->value.as_double);
         }
       }
     }
@@ -1651,7 +1651,7 @@
       EXPECT_STREQ(".", element->value.as_string);
       element = root->value.as_array.values[1];
       EXPECT_EQ(Dart_CObject_kDouble, element->type);
-      EXPECT_STREQ(2.72, element->value.as_double);
+      EXPECT_STREQ("2.72", element->value.as_double);
       for (int i = 2; i < kArrayLength; i++) {
         Dart_CObject* element = root->value.as_array.values[i];
         if ((i % 2) == 0) {
@@ -1662,7 +1662,7 @@
           // Double values are expected to not be canonicalized in messages.
           EXPECT_NE(root->value.as_array.values[1], element);
           EXPECT_EQ(Dart_CObject_kDouble, element->type);
-          EXPECT_STREQ(2.72, element->value.as_double);
+          EXPECT_STREQ("2.72", element->value.as_double);
         }
       }
     }
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index 2bdde95..defc700 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -287,12 +287,12 @@
   if (!code.IsNull()) {
     // Optimized frames have a stack map. We need to visit the frame based
     // on the stack map.
-    Array maps;
-    maps = Array::null();
-    StackMap map;
+    CompressedStackMaps maps;
+    maps = code.compressed_stackmaps();
+    CompressedStackMapsIterator it(maps);
     const uword start = Instructions::PayloadStart(code.instructions());
-    map = code.GetStackMap(pc() - start, &maps, &map);
-    if (!map.IsNull()) {
+    const uint32_t pc_offset = pc() - start;
+    if (it.Find(pc_offset)) {
 #if !defined(TARGET_ARCH_DBC)
       if (is_interpreted()) {
         UNIMPLEMENTED();
@@ -311,11 +311,11 @@
       // The spill slots and any saved registers are described in the stack
       // map.  The outgoing arguments are assumed to be tagged; the number
       // of outgoing arguments is not explicitly tracked.
-      intptr_t length = map.Length();
+
       // Spill slots are at the 'bottom' of the frame.
-      intptr_t spill_slot_count = length - map.SlowPathBitCount();
+      intptr_t spill_slot_count = it.spill_slot_bit_count();
       for (intptr_t bit = 0; bit < spill_slot_count; ++bit) {
-        if (map.IsObject(bit)) {
+        if (it.IsObject(bit)) {
           visitor->VisitPointer(last);
         }
         --last;
@@ -323,8 +323,8 @@
 
       // The live registers at the 'top' of the frame comprise the rest of the
       // stack map.
-      for (intptr_t bit = length - 1; bit >= spill_slot_count; --bit) {
-        if (map.IsObject(bit)) {
+      for (intptr_t bit = it.length() - 1; bit >= spill_slot_count; --bit) {
+        if (it.IsObject(bit)) {
           visitor->VisitPointer(first);
         }
         ++first;
@@ -363,12 +363,11 @@
       // The DBC registers are described in the stack map.
       // The outgoing arguments are assumed to be tagged; the number
       // of outgoing arguments is not explicitly tracked.
-      ASSERT(map.SlowPathBitCount() == 0);
 
       // Visit DBC registers that contain tagged values.
-      intptr_t length = map.Length();
+      intptr_t length = it.length();
       for (intptr_t bit = 0; bit < length; ++bit) {
-        if (map.IsObject(bit)) {
+        if (it.IsObject(bit)) {
           visitor->VisitPointer(first + bit);
         }
       }
@@ -381,7 +380,12 @@
       return;
     }
 
-    // No stack map, fall through.
+    // If we are missing a stack map for a given PC offset, this must either be
+    // unoptimized code, code with no stack map information at all, or the entry
+    // to an osr function. In each of these cases, all stack slots contain
+    // tagged pointers, so fall through.
+    ASSERT(!code.is_optimized() || maps.IsNull() ||
+           (pc_offset == code.EntryPoint() - code.PayloadStart()));
   }
 
 #if !defined(TARGET_ARCH_DBC)
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index c95b589..cdbd809 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -57,6 +57,7 @@
   V(CompleterFuture, "future")                                                 \
   V(CompleterGetFuture, "get:future")                                          \
   V(CompleterSyncConstructor, "Completer.sync")                                \
+  V(CompressedStackMaps, "CompressedStackMaps")                                \
   V(ConstructorStacktracePrefix, "new ")                                       \
   V(Context, "Context")                                                        \
   V(ContextScope, "ContextScope")                                              \
@@ -245,7 +246,6 @@
   V(SpaceIsFromSpace, " is from ")                                             \
   V(SpaceOfSpace, " of ")                                                      \
   V(SpaceWhereNewLine, " where\n")                                             \
-  V(StackMap, "StackMap")                                                      \
   V(StackOverflowError, "StackOverflowError")                                  \
   V(StackTraceParameter, ":stack_trace")                                       \
   V(StackTraceVar, ":stack_trace_var")                                         \
diff --git a/runtime/vm/timeline.cc b/runtime/vm/timeline.cc
index bad38fd..775d1ae 100644
--- a/runtime/vm/timeline.cc
+++ b/runtime/vm/timeline.cc
@@ -1113,8 +1113,7 @@
 #if defined(HOST_OS_FUCHSIA) && !defined(FUCHSIA_SDK)
   return trace_generate_nonce();
 #else
-  uint32_t next =
-      static_cast<uint32_t>(AtomicOperations::FetchAndIncrement(&async_id_));
+  uint32_t next = static_cast<uint32_t>(async_id_.fetch_add(1u));
   return static_cast<int64_t>(next);
 #endif
 }
diff --git a/runtime/vm/timeline.h b/runtime/vm/timeline.h
index 5805581..2239982 100644
--- a/runtime/vm/timeline.h
+++ b/runtime/vm/timeline.h
@@ -7,6 +7,7 @@
 
 #include "include/dart_tools_api.h"
 
+#include "platform/atomic.h"
 #include "vm/allocation.h"
 #include "vm/bitfield.h"
 #include "vm/globals.h"
@@ -740,7 +741,7 @@
   int64_t TimeExtentMicros() const;
 
   Mutex lock_;
-  uintptr_t async_id_;
+  RelaxedAtomic<uintptr_t> async_id_;
   int64_t time_low_micros_;
   int64_t time_high_micros_;
 
diff --git a/runtime/vm/timer.h b/runtime/vm/timer.h
index 94b67ea..922c43a 100644
--- a/runtime/vm/timer.h
+++ b/runtime/vm/timer.h
@@ -33,9 +33,9 @@
     ASSERT(running());
     stop_ = OS::GetCurrentMonotonicMicros();
     int64_t elapsed = ElapsedMicros();
-    max_contiguous_ = Utils::Maximum(max_contiguous_, elapsed);
+    max_contiguous_ = Utils::Maximum(max_contiguous_.load(), elapsed);
     // Make increment atomic in case it occurs in parallel with aggregation.
-    AtomicOperations::IncrementInt64By(&total_, elapsed);
+    total_.fetch_add(elapsed);
     running_ = false;
   }
 
@@ -71,9 +71,7 @@
            (max_contiguous_ == 0) && !running_;
   }
 
-  void AddTotal(const Timer& other) {
-    AtomicOperations::IncrementInt64By(&total_, other.total_);
-  }
+  void AddTotal(const Timer& other) { total_.fetch_add(other.total_); }
 
   // Accessors.
   bool report() const { return report_; }
@@ -87,10 +85,10 @@
     return stop_ - start_;
   }
 
-  ALIGN8 int64_t start_;
-  ALIGN8 int64_t stop_;
-  ALIGN8 int64_t total_;
-  ALIGN8 int64_t max_contiguous_;
+  RelaxedAtomic<int64_t> start_;
+  RelaxedAtomic<int64_t> stop_;
+  RelaxedAtomic<int64_t> total_;
+  RelaxedAtomic<int64_t> max_contiguous_;
   bool report_;
   bool running_;
   const char* message_;
diff --git a/runtime/vm/zone.cc b/runtime/vm/zone.cc
index cdb8ba4..bcd37eb 100644
--- a/runtime/vm/zone.cc
+++ b/runtime/vm/zone.cc
@@ -29,9 +29,7 @@
 
   // Allocate or delete individual segments.
   static Segment* New(intptr_t size, Segment* next);
-  static Segment* NewLarge(intptr_t size, Segment* next);
   static void DeleteSegmentList(Segment* segment);
-  static void DeleteLargeSegmentList(Segment* segment);
   static void IncrementMemoryCapacity(uintptr_t size);
   static void DecrementMemoryCapacity(uintptr_t size);
 
@@ -47,28 +45,48 @@
   DISALLOW_IMPLICIT_CONSTRUCTORS(Segment);
 };
 
-Zone::Segment* Zone::Segment::New(intptr_t size, Zone::Segment* next) {
-  ASSERT(size >= 0);
-  Segment* result = reinterpret_cast<Segment*>(malloc(size));
-  if (result == NULL) {
-    OUT_OF_MEMORY();
-  }
-#ifdef DEBUG
-  // Zap the entire allocated segment (including the header).
-  memset(result, kZapUninitializedByte, size);
-#endif
-  result->next_ = next;
-  result->size_ = size;
-  result->memory_ = nullptr;
-  result->alignment_ = nullptr;  // Avoid unused variable warnings.
-  IncrementMemoryCapacity(size);
-  return result;
+// tcmalloc and jemalloc have both been observed to hold onto lots of free'd
+// zone segments (jemalloc to the point of causing OOM), so instead of using
+// malloc to allocate segments, we allocate directly from mmap/zx_vmo_create/
+// VirtualAlloc, and cache a small number of the normal sized segments.
+static constexpr intptr_t kSegmentCacheCapacity = 16;  // 1 MB of Segments
+static Mutex* segment_cache_mutex = nullptr;
+static VirtualMemory* segment_cache[kSegmentCacheCapacity] = {nullptr};
+static intptr_t segment_cache_size = 0;
+
+void Zone::Init() {
+  ASSERT(segment_cache_mutex == nullptr);
+  segment_cache_mutex = new Mutex(NOT_IN_PRODUCT("segment_cache_mutex"));
 }
 
-Zone::Segment* Zone::Segment::NewLarge(intptr_t size, Zone::Segment* next) {
+void Zone::Cleanup() {
+  {
+    MutexLocker ml(segment_cache_mutex);
+    ASSERT(segment_cache_size >= 0);
+    ASSERT(segment_cache_size <= kSegmentCacheCapacity);
+    while (segment_cache_size > 0) {
+      delete segment_cache[--segment_cache_size];
+    }
+  }
+  delete segment_cache_mutex;
+  segment_cache_mutex = nullptr;
+}
+
+Zone::Segment* Zone::Segment::New(intptr_t size, Zone::Segment* next) {
   size = Utils::RoundUp(size, VirtualMemory::PageSize());
-  VirtualMemory* memory = VirtualMemory::Allocate(size, false, "dart-zone");
-  if (memory == NULL) {
+  VirtualMemory* memory = nullptr;
+  if (size == kSegmentSize) {
+    MutexLocker ml(segment_cache_mutex);
+    ASSERT(segment_cache_size >= 0);
+    ASSERT(segment_cache_size <= kSegmentCacheCapacity);
+    if (segment_cache_size > 0) {
+      memory = segment_cache[--segment_cache_size];
+    }
+  }
+  if (memory == nullptr) {
+    memory = VirtualMemory::Allocate(size, false, "dart-zone");
+  }
+  if (memory == nullptr) {
     OUT_OF_MEMORY();
   }
   Segment* result = reinterpret_cast<Segment*>(memory->start());
@@ -90,21 +108,8 @@
 void Zone::Segment::DeleteSegmentList(Segment* head) {
   Segment* current = head;
   while (current != NULL) {
-    DecrementMemoryCapacity(current->size());
-    Segment* next = current->next();
-#ifdef DEBUG
-    // Zap the entire current segment (including the header).
-    memset(current, kZapDeletedByte, current->size());
-#endif
-    free(current);
-    current = next;
-  }
-}
-
-void Zone::Segment::DeleteLargeSegmentList(Segment* head) {
-  Segment* current = head;
-  while (current != NULL) {
-    DecrementMemoryCapacity(current->size());
+    intptr_t size = current->size();
+    DecrementMemoryCapacity(size);
     Segment* next = current->next();
     VirtualMemory* memory = current->memory();
 #ifdef DEBUG
@@ -112,6 +117,16 @@
     memset(current, kZapDeletedByte, current->size());
 #endif
     LSAN_UNREGISTER_ROOT_REGION(current, sizeof(*current));
+
+    if (size == kSegmentSize) {
+      MutexLocker ml(segment_cache_mutex);
+      ASSERT(segment_cache_size >= 0);
+      ASSERT(segment_cache_size <= kSegmentCacheCapacity);
+      if (segment_cache_size < kSegmentCacheCapacity) {
+        segment_cache[segment_cache_size++] = memory;
+        memory = nullptr;
+      }
+    }
     delete memory;
     current = next;
   }
@@ -172,7 +187,7 @@
     Segment::DeleteSegmentList(head_);
   }
   if (large_segments_ != NULL) {
-    Segment::DeleteLargeSegmentList(large_segments_);
+    Segment::DeleteSegmentList(large_segments_);
   }
 // Reset zone state.
 #ifdef DEBUG
@@ -259,7 +274,7 @@
   // Create a new large segment and chain it up.
   // Account for book keeping fields in size.
   size += Utils::RoundUp(sizeof(Segment), kAlignment);
-  large_segments_ = Segment::NewLarge(size, large_segments_);
+  large_segments_ = Segment::New(size, large_segments_);
 
   uword result = Utils::RoundUp(large_segments_->start(), kAlignment);
   return result;
diff --git a/runtime/vm/zone.h b/runtime/vm/zone.h
index 6f11bf7..edb0cb8 100644
--- a/runtime/vm/zone.h
+++ b/runtime/vm/zone.h
@@ -85,6 +85,9 @@
   // All pointers returned from AllocateUnsafe() and New() have this alignment.
   static const intptr_t kAlignment = kDoubleSize;
 
+  static void Init();
+  static void Cleanup();
+
  private:
   Zone();
   ~Zone();  // Delete all memory associated with the zone.
diff --git a/samples/ffi/coordinate.dart b/samples/ffi/coordinate.dart
index f8ac7d48..2246f03 100644
--- a/samples/ffi/coordinate.dart
+++ b/samples/ffi/coordinate.dart
@@ -4,37 +4,34 @@
 
 library FfiTest;
 
-import 'dart:ffi' as ffi;
+import 'dart:ffi';
+
+import 'package:ffi/ffi.dart' as ffi;
 
 /// Sample struct for dart:ffi library.
-@ffi.struct
-class Coordinate extends ffi.Pointer<ffi.Void> {
-  @ffi.Double()
+class Coordinate extends Struct {
+  @Double()
   double x;
 
-  @ffi.Double()
+  @Double()
   double y;
 
-  @ffi.Pointer()
-  Coordinate next;
+  Pointer<Coordinate> next;
 
   // Implementation generated by @ffi.struct annotation.
   external static int sizeOf();
 
-  Coordinate offsetBy(int offsetInBytes) =>
-      super.offsetBy(offsetInBytes).cast();
-
-  Coordinate elementAt(int index) => offsetBy(sizeOf() * index);
+  Coordinate elementAt(int index) => addressOf.elementAt(index).ref;
 
   static Coordinate allocate({int count: 1}) =>
-      ffi.allocate<ffi.Uint8>(count: count * sizeOf()).cast();
+      ffi.allocate<Coordinate>(count: count).ref;
 
   /// Allocate a new [Coordinate] in C memory and populate its fields.
   factory Coordinate(double x, double y, Coordinate next) {
     Coordinate result = Coordinate.allocate()
       ..x = x
       ..y = y
-      ..next = next;
+      ..next = next.addressOf;
     return result;
   }
 }
diff --git a/samples/ffi/sample_ffi_data.dart b/samples/ffi/sample_ffi_data.dart
index ba05601..7b34917 100644
--- a/samples/ffi/sample_ffi_data.dart
+++ b/samples/ffi/sample_ffi_data.dart
@@ -2,75 +2,61 @@
 // for 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:ffi' as ffi;
+import 'dart:ffi';
+import 'package:ffi/ffi.dart';
 
 main(List<String> arguments) {
   print('start main');
 
   {
     // basic operation: allocate, get, set, and free
-    ffi.Pointer<ffi.Int64> p = ffi.allocate();
-    p.store(42);
-    int pValue = p.load();
+    Pointer<Int64> p = allocate();
+    p.value = 42;
+    int pValue = p.value;
     print('${p.runtimeType} value: ${pValue}');
-    p.free();
+    free(p);
   }
 
   {
     // undefined behavior before set
-    ffi.Pointer<ffi.Int64> p = ffi.allocate();
-    int pValue = p.load();
+    Pointer<Int64> p = allocate();
+    int pValue = p.value;
     print('If not set, returns garbage: ${pValue}');
-    p.free();
+    free(p);
   }
 
   {
     // pointers can be created from an address
-    ffi.Pointer<ffi.Int64> pHelper = ffi.allocate();
-    pHelper.store(1337);
+    Pointer<Int64> pHelper = allocate();
+    pHelper.value = 1337;
 
     int address = pHelper.address;
     print('Address: ${address}');
 
-    ffi.Pointer<ffi.Int64> p = ffi.fromAddress(address);
-    print('${p.runtimeType} value: ${p.load<int>()}');
+    Pointer<Int64> p = Pointer.fromAddress(address);
+    print('${p.runtimeType} value: ${p.value}');
 
-    pHelper.free();
+    free(pHelper);
   }
 
   {
     // address is zeroed out after free
-    ffi.Pointer<ffi.Int64> p = ffi.allocate();
-    p.free();
+    Pointer<Int64> p = allocate();
+    free(p);
     print('After free, address is zero: ${p.address}');
   }
 
   {
-    // pointer arithmetic can be done with element offsets or bytes
-    ffi.Pointer<ffi.Int64> p1 = ffi.allocate<ffi.Int64>(count: 2);
-    print('p1 address: ${p1.address}');
-
-    ffi.Pointer<ffi.Int64> p2 = p1.elementAt(1);
-    print('p1.elementAt(1) address: ${p2.address}');
-    p2.store(100);
-
-    ffi.Pointer<ffi.Int64> p3 = p1.offsetBy(8);
-    print('p1.offsetBy(8) address: ${p3.address}');
-    print('p1.offsetBy(8) value: ${p3.load<int>()}');
-    p1.free();
-  }
-
-  {
     // allocating too much throws an exception
     try {
       int maxMint = 9223372036854775807; // 2^63 - 1
-      ffi.allocate<ffi.Int64>(count: maxMint);
+      allocate<Int64>(count: maxMint);
     } on RangeError {
       print('Expected exception on allocating too much');
     }
     try {
       int maxInt1_8 = 1152921504606846975; // 2^60 -1
-      ffi.allocate<ffi.Int64>(count: maxInt1_8);
+      allocate<Int64>(count: maxInt1_8);
     } on ArgumentError {
       print('Expected exception on allocating too much');
     }
@@ -79,83 +65,83 @@
   {
     // pointers can be cast into another type
     // resulting in the corresponding bits read
-    ffi.Pointer<ffi.Int64> p1 = ffi.allocate();
-    p1.store(9223372036854775807); // 2^63 - 1
+    Pointer<Int64> p1 = allocate();
+    p1.value = 9223372036854775807; // 2^63 - 1
 
-    ffi.Pointer<ffi.Int32> p2 = p1.cast();
-    print('${p2.runtimeType} value: ${p2.load<int>()}'); // -1
+    Pointer<Int32> p2 = p1.cast();
+    print('${p2.runtimeType} value: ${p2.value}'); // -1
 
-    ffi.Pointer<ffi.Int32> p3 = p2.elementAt(1);
-    print('${p3.runtimeType} value: ${p3.load<int>()}'); // 2^31 - 1
+    Pointer<Int32> p3 = p2.elementAt(1);
+    print('${p3.runtimeType} value: ${p3.value}'); // 2^31 - 1
 
-    p1.free();
+    free(p1);
   }
 
   {
     // data can be tightly packed in memory
-    ffi.Pointer<ffi.Int8> p = ffi.allocate(count: 8);
+    Pointer<Int8> p = allocate(count: 8);
     for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
-      p.elementAt(i).store(i * 3);
+      p.elementAt(i).value = i * 3;
     }
     for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
-      print('p.elementAt($i) value: ${p.elementAt(i).load<int>()}');
+      print('p.elementAt($i) value: ${p.elementAt(i).value}');
     }
-    p.free();
+    free(p);
   }
 
   {
     // exception on storing a value that does not fit
-    ffi.Pointer<ffi.Int32> p11 = ffi.allocate();
+    Pointer<Int32> p11 = allocate();
 
     try {
-      p11.store(9223372036854775807);
+      p11.value = 9223372036854775807;
     } on ArgumentError {
       print('Expected exception on calling set with a value that does not fit');
     }
 
-    p11.free();
+    free(p11);
   }
 
   {
     // doubles
-    ffi.Pointer<ffi.Double> p = ffi.allocate();
-    p.store(3.14159265359);
-    print('${p.runtimeType} value: ${p.load<double>()}');
-    p.store(3.14);
-    print('${p.runtimeType} value: ${p.load<double>()}');
-    p.free();
+    Pointer<Double> p = allocate();
+    p.value = 3.14159265359;
+    print('${p.runtimeType} value: ${p.value}');
+    p.value = 3.14;
+    print('${p.runtimeType} value: ${p.value}');
+    free(p);
   }
 
   {
     // floats
-    ffi.Pointer<ffi.Float> p = ffi.allocate();
-    p.store(3.14159265359);
-    print('${p.runtimeType} value: ${p.load<double>()}');
-    p.store(3.14);
-    print('${p.runtimeType} value: ${p.load<double>()}');
-    p.free();
+    Pointer<Float> p = allocate();
+    p.value = 3.14159265359;
+    print('${p.runtimeType} value: ${p.value}');
+    p.value = 3.14;
+    print('${p.runtimeType} value: ${p.value}');
+    free(p);
   }
 
   {
-    // ffi.IntPtr varies in size based on whether the platform is 32 or 64 bit
+    // IntPtr varies in size based on whether the platform is 32 or 64 bit
     // addresses of pointers fit in this size
-    ffi.Pointer<ffi.IntPtr> p = ffi.allocate();
+    Pointer<IntPtr> p = allocate();
     int p14addr = p.address;
-    p.store(p14addr);
-    int pValue = p.load();
+    p.value = p14addr;
+    int pValue = p.value;
     print('${p.runtimeType} value: ${pValue}');
-    p.free();
+    free(p);
   }
 
   {
     // void pointers are unsized
     // the size of the element it is pointing to is undefined
-    // this means they cannot be ffi.allocated, read, or written
+    // this means they cannot be allocated, read, or written
     // this would would fail to compile:
-    // ffi.allocate<ffi.Void>();
+    // allocate<Void>();
 
-    ffi.Pointer<ffi.IntPtr> p1 = ffi.allocate();
-    ffi.Pointer<ffi.Void> p2 = p1.cast();
+    Pointer<IntPtr> p1 = allocate();
+    Pointer<Void> p2 = p1.cast();
     print('${p2.runtimeType} address: ${p2.address}');
 
     // this fails to compile, we cannot read something unsized
@@ -164,98 +150,98 @@
     // this fails to compile, we cannot write something unsized
     // p2.store(1234);
 
-    p1.free();
+    free(p1);
   }
 
   {
     // pointer to a pointer to something
-    ffi.Pointer<ffi.Int16> pHelper = ffi.allocate();
-    pHelper.store(17);
+    Pointer<Int16> pHelper = allocate();
+    pHelper.value = 17;
 
-    ffi.Pointer<ffi.Pointer<ffi.Int16>> p = ffi.allocate();
+    Pointer<Pointer<Int16>> p = allocate();
 
     // storing into a pointer pointer automatically unboxes
-    p.store(pHelper);
+    p.value = pHelper;
 
     // reading from a pointer pointer automatically boxes
-    ffi.Pointer<ffi.Int16> pHelper2 = p.load();
-    print('${pHelper2.runtimeType} value: ${pHelper2.load<int>()}');
+    Pointer<Int16> pHelper2 = p.value;
+    print('${pHelper2.runtimeType} value: ${pHelper2.value}');
 
-    int pValue = p.load<ffi.Pointer<ffi.Int16>>().load();
+    int pValue = p.value.value;
     print('${p.runtimeType} value\'s value: ${pValue}');
 
-    p.free();
-    pHelper.free();
+    free(p);
+    free(pHelper);
   }
 
   {
     // the pointer to pointer types must match up
-    ffi.Pointer<ffi.Int8> pHelper = ffi.allocate();
-    pHelper.store(123);
+    Pointer<Int8> pHelper = allocate();
+    pHelper.value = 123;
 
-    ffi.Pointer<ffi.Pointer<ffi.Int16>> p = ffi.allocate();
+    Pointer<Pointer<Int16>> p = allocate();
 
     // this fails to compile due to type mismatch
     // p.store(pHelper);
 
-    pHelper.free();
-    p.free();
+    free(pHelper);
+    free(p);
   }
 
   {
     // null pointer in Dart points to address 0 in c++
-    ffi.Pointer<ffi.Pointer<ffi.Int8>> pointerToPointer = ffi.allocate();
-    ffi.Pointer<ffi.Int8> value = null;
-    pointerToPointer.store(value);
-    value = pointerToPointer.load();
+    Pointer<Pointer<Int8>> pointerToPointer = allocate();
+    Pointer<Int8> value = null;
+    pointerToPointer.value = value;
+    value = pointerToPointer.value;
     print("Loading a pointer to the 0 address is null: ${value}");
-    pointerToPointer.free();
+    free(pointerToPointer);
   }
 
   {
     // sizeof returns element size in bytes
-    print('sizeOf<ffi.Double>(): ${ffi.sizeOf<ffi.Double>()}');
-    print('sizeOf<ffi.Int16>(): ${ffi.sizeOf<ffi.Int16>()}');
-    print('sizeOf<ffi.IntPtr>(): ${ffi.sizeOf<ffi.IntPtr>()}');
+    print('sizeOf<Double>(): ${sizeOf<Double>()}');
+    print('sizeOf<Int16>(): ${sizeOf<Int16>()}');
+    print('sizeOf<IntPtr>(): ${sizeOf<IntPtr>()}');
   }
 
   {
-    // only concrete sub types of NativeType can be ffi.allocated
+    // only concrete sub types of NativeType can be allocated
     // this would fail to compile:
-    // ffi.allocate();
+    // allocate();
   }
 
   {
     // only concrete sub types of NativeType can be asked for size
     // this would fail to compile:
-    // ffi.sizeOf();
+    // sizeOf();
   }
 
   {
-    // with ffi.IntPtr pointers, one can manually setup aribtrary data
+    // with IntPtr pointers, one can manually setup aribtrary data
     // structres in C memory.
 
-    void createChain(ffi.Pointer<ffi.IntPtr> head, int length, int value) {
+    void createChain(Pointer<IntPtr> head, int length, int value) {
       if (length == 0) {
-        head.store(value);
+        head.value = value;
         return;
       }
-      ffi.Pointer<ffi.IntPtr> next = ffi.allocate<ffi.IntPtr>();
-      head.store(next.address);
+      Pointer<IntPtr> next = allocate<IntPtr>();
+      head.value = next.address;
       createChain(next, length - 1, value);
     }
 
-    int getChainValue(ffi.Pointer<ffi.IntPtr> head, int length) {
+    int getChainValue(Pointer<IntPtr> head, int length) {
       if (length == 0) {
-        return head.load();
+        return head.value;
       }
-      ffi.Pointer<ffi.IntPtr> next = ffi.fromAddress(head.load());
+      Pointer<IntPtr> next = Pointer.fromAddress(head.value);
       return getChainValue(next, length - 1);
     }
 
-    void freeChain(ffi.Pointer<ffi.IntPtr> head, int length) {
-      ffi.Pointer<ffi.IntPtr> next = ffi.fromAddress(head.load());
-      head.free();
+    void freeChain(Pointer<IntPtr> head, int length) {
+      Pointer<IntPtr> next = Pointer.fromAddress(head.value);
+      free(head);
       if (length == 0) {
         return;
       }
@@ -263,7 +249,7 @@
     }
 
     int length = 10;
-    ffi.Pointer<ffi.IntPtr> head = ffi.allocate();
+    Pointer<IntPtr> head = allocate();
     createChain(head, length, 512);
     int tailValue = getChainValue(head, length);
     print('tailValue: ${tailValue}');
diff --git a/samples/ffi/sample_ffi_functions.dart b/samples/ffi/sample_ffi_functions.dart
index 9d326e9..4275b3d 100644
--- a/samples/ffi/sample_ffi_functions.dart
+++ b/samples/ffi/sample_ffi_functions.dart
@@ -4,6 +4,8 @@
 
 import 'dart:ffi' as ffi;
 
+import 'package:ffi/ffi.dart';
+
 import 'dylib_utils.dart';
 
 typedef NativeUnaryOp = ffi.Int32 Function(ffi.Int32);
@@ -193,7 +195,7 @@
     // pass an array / pointer as argument
     Int64PointerUnOp assign1337Index1 = ffiTestFunctions
         .lookupFunction<Int64PointerUnOp, Int64PointerUnOp>("Assign1337Index1");
-    ffi.Pointer<ffi.Int64> p2 = ffi.allocate(count: 2);
+    ffi.Pointer<ffi.Int64> p2 = allocate(count: 2);
     p2.store(42);
     p2.elementAt(1).store(1000);
     print(p2.elementAt(1).address.toRadixString(16));
@@ -258,11 +260,11 @@
     print(result);
     print(result.runtimeType);
 
-    ffi.Pointer<ffi.Int64> p2 = ffi.allocate(count: 2);
+    ffi.Pointer<ffi.Int64> p2 = allocate(count: 2);
     result = nullableInt64ElemAt1(p2);
     print(result);
     print(result.runtimeType);
-    p2.free();
+    free(p2);
   }
 
   print("end main");
diff --git a/samples/ffi/sample_ffi_functions_callbacks.dart b/samples/ffi/sample_ffi_functions_callbacks.dart
index 8549377..62ed355 100644
--- a/samples/ffi/sample_ffi_functions_callbacks.dart
+++ b/samples/ffi/sample_ffi_functions_callbacks.dart
@@ -46,7 +46,7 @@
         ffiTestFunctions.lookup("CoordinateUnOpTrice");
     CoordinateTrice coordinateUnOpTrice = p2.asFunction();
     Coordinate c1 = Coordinate(10.0, 20.0, null);
-    c1.next = c1;
+    c1.next = c1.addressOf;
     Coordinate result = coordinateUnOpTrice(transposeCoordinatePointer, c1);
     print(result.runtimeType);
     print(result.x);
@@ -67,7 +67,7 @@
 
   {
     ffi.Pointer<ffi.NativeFunction<NativeIntptrBinOp>> pointer =
-        ffi.fromFunction(myPlus);
+        ffi.Pointer.fromFunction(myPlus);
     print(pointer);
 
     ffi.Pointer<ffi.NativeFunction<NativeApplyTo42And74Type>> p17 =
diff --git a/samples/ffi/sample_ffi_functions_structs.dart b/samples/ffi/sample_ffi_functions_structs.dart
index d2b1e41..c166b8b 100644
--- a/samples/ffi/sample_ffi_functions_structs.dart
+++ b/samples/ffi/sample_ffi_functions_structs.dart
@@ -24,7 +24,7 @@
 
     Coordinate c1 = Coordinate(10.0, 20.0, null);
     Coordinate c2 = Coordinate(42.0, 84.0, c1);
-    c1.next = c2;
+    c1.next = c2.addressOf;
 
     Coordinate result = f1(c1);
 
@@ -48,13 +48,13 @@
     Coordinate c3 = c1.elementAt(2);
     c1.x = 10.0;
     c1.y = 10.0;
-    c1.next = c3;
+    c1.next = c3.addressOf;
     c2.x = 20.0;
     c2.y = 20.0;
-    c2.next = c1;
+    c2.next = c1.addressOf;
     c3.x = 30.0;
     c3.y = 30.0;
-    c3.next = c2;
+    c3.next = c2.addressOf;
 
     Coordinate result = f1(c1);
 
diff --git a/samples/ffi/sample_ffi_structs.dart b/samples/ffi/sample_ffi_structs.dart
index fd757e5..471f23f 100644
--- a/samples/ffi/sample_ffi_structs.dart
+++ b/samples/ffi/sample_ffi_structs.dart
@@ -2,7 +2,9 @@
 // for 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:ffi' as ffi;
+import 'dart:ffi';
+
+import 'package:ffi/ffi.dart';
 
 import 'coordinate.dart';
 
@@ -14,17 +16,17 @@
     Coordinate c1 = Coordinate(10.0, 10.0, null);
     Coordinate c2 = Coordinate(20.0, 20.0, c1);
     Coordinate c3 = Coordinate(30.0, 30.0, c2);
-    c1.next = c3;
+    c1.next = c3.addressOf;
 
     Coordinate currentCoordinate = c1;
     for (var i in [0, 1, 2, 3, 4]) {
-      currentCoordinate = currentCoordinate.next;
+      currentCoordinate = currentCoordinate.next.ref;
       print("${currentCoordinate.x}; ${currentCoordinate.y}");
     }
 
-    c1.free();
-    c2.free();
-    c3.free();
+    free(c1.addressOf);
+    free(c2.addressOf);
+    free(c3.addressOf);
   }
 
   {
@@ -34,29 +36,29 @@
     Coordinate c3 = c1.elementAt(2);
     c1.x = 10.0;
     c1.y = 10.0;
-    c1.next = c3;
+    c1.next = c3.addressOf;
     c2.x = 20.0;
     c2.y = 20.0;
-    c2.next = c1;
+    c2.next = c1.addressOf;
     c3.x = 30.0;
     c3.y = 30.0;
-    c3.next = c2;
+    c3.next = c2.addressOf;
 
     Coordinate currentCoordinate = c1;
     for (var i in [0, 1, 2, 3, 4]) {
-      currentCoordinate = currentCoordinate.next;
+      currentCoordinate = currentCoordinate.next.ref;
       print("${currentCoordinate.x}; ${currentCoordinate.y}");
     }
 
-    c1.free();
+    free(c1.addressOf);
   }
 
   {
     Coordinate c = Coordinate(10, 10, null);
     print(c is Coordinate);
-    print(c is ffi.Pointer<ffi.Void>);
-    print(c is ffi.Pointer);
-    c.free();
+    print(c is Pointer<Void>);
+    print(c is Pointer);
+    free(c.addressOf);
   }
 
   print("end main");
diff --git a/samples/ffi/sqlite/docs/sqlite-tutorial.md b/samples/ffi/sqlite/docs/sqlite-tutorial.md
index f9db349..9b8e7e1 100644
--- a/samples/ffi/sqlite/docs/sqlite-tutorial.md
+++ b/samples/ffi/sqlite/docs/sqlite-tutorial.md
@@ -79,8 +79,8 @@
 
 ```dart
 Pointer<Uint8> p = allocate(); // Infers type argument allocate<Uint8>(), and allocates 1 byte.
-p.store(123);                  // Stores a Dart int into this C int8.
-int v = p.load();              // Infers type argument p.load<int>(), and loads a value from C memory.
+p.value = 123;                 // Stores a Dart int into this C int8.
+int v = p.value;               // Loads a value from C memory.
 ```
 
 Note that you can only load a Dart `int` from a C `Uint8`.
@@ -92,10 +92,10 @@
 
 ```dart
 CString string = allocate(count: 4).cast(); // Allocates 4 bytes and casts it to a string.
-string.store(73);                           // Stores 'F' at index 0.
-string.elementAt(1).store(73);              // Stores 'F' at index 1.
-string.elementAt(2).store(70);              // Stores 'I' at index 2.
-string.elementAt(3).store(0);               // Null terminates the string.
+string.value = 73;                          // Stores 'F' at index 0.
+string[1] = 73;                             // Stores 'F' at index 1.
+string[2] = 70;                             // Stores 'I' at index 2.
+string[3] = 0;                              // Null terminates the string.
 ```
 
 We wrap the above logic of allocating strings in the constructor `CString.allocate`.
@@ -106,14 +106,14 @@
 Pointer<StatementPointer> statementOut = allocate();
 CString queryC = CString.allocate(query);
 int resultCode = sqlite3_prepare_v2(
-    _database, queryC, -1, statementOut, fromAddress(0));
+    _database, queryC, -1, statementOut, nullptr);
 ```
 
 With `dart:ffi` we are responsible for freeing C memory that we allocate.
 So after calling `sqlite3_prepare_v2` we read out the statement pointer, and free the statement pointer pointer and `CString` which held the query string.
 
 ```
-StatementPointer statement = statementOut.load();
+StatementPointer statement = statementOut.value;
 statementOut.free();
 queryC.free();
 ```
diff --git a/samples/ffi/sqlite/example/main.dart b/samples/ffi/sqlite/example/main.dart
index f54e7d3..480ef42 100644
--- a/samples/ffi/sqlite/example/main.dart
+++ b/samples/ffi/sqlite/example/main.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 "package:test/test.dart";
-
 import "../lib/sqlite.dart";
 
 void main() {
diff --git a/samples/ffi/sqlite/lib/src/bindings/bindings.dart b/samples/ffi/sqlite/lib/src/bindings/bindings.dart
index a248716..0271506 100644
--- a/samples/ffi/sqlite/lib/src/bindings/bindings.dart
+++ b/samples/ffi/sqlite/lib/src/bindings/bindings.dart
@@ -3,8 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import "dart:ffi";
+import "package:ffi/ffi.dart";
 
-import "../ffi/utf8.dart";
 import "../ffi/dylib_utils.dart";
 
 import "signatures.dart";
diff --git a/samples/ffi/sqlite/lib/src/bindings/signatures.dart b/samples/ffi/sqlite/lib/src/bindings/signatures.dart
index 8994577..2f38dad 100644
--- a/samples/ffi/sqlite/lib/src/bindings/signatures.dart
+++ b/samples/ffi/sqlite/lib/src/bindings/signatures.dart
@@ -4,7 +4,7 @@
 
 import "dart:ffi";
 
-import "../ffi/utf8.dart";
+import "package:ffi/ffi.dart";
 
 import "types.dart";
 
diff --git a/samples/ffi/sqlite/lib/src/bindings/types.dart b/samples/ffi/sqlite/lib/src/bindings/types.dart
index f536b91..494cdef 100644
--- a/samples/ffi/sqlite/lib/src/bindings/types.dart
+++ b/samples/ffi/sqlite/lib/src/bindings/types.dart
@@ -4,8 +4,6 @@
 
 import "dart:ffi";
 
-import "../ffi/utf8.dart";
-
 /// Database Connection Handle
 ///
 /// Each open SQLite database is represented by a pointer to an instance of
@@ -15,7 +13,7 @@
 /// is its destructor.  There are many other interfaces (such as
 /// [sqlite3_prepare_v2()], [sqlite3_create_function()], and
 /// [sqlite3_busy_timeout()] to name but three) that are methods on an
-class Database extends Struct<Database> {}
+class Database extends Struct {}
 
 /// SQL Statement Object
 ///
@@ -38,7 +36,7 @@
 ///
 /// Refer to documentation on individual methods above for additional
 /// information.
-class Statement extends Struct<Statement> {}
+class Statement extends Struct {}
 
 /// Dynamically Typed Value Object
 ///
@@ -74,4 +72,4 @@
 /// [sqlite3_result_value()] and [sqlite3_bind_value()].
 /// The [sqlite3_value_blob | sqlite3_value_type()] family of
 /// interfaces require protected sqlite3_value objects.
-class Value extends Struct<Value> {}
+class Value extends Struct {}
diff --git a/samples/ffi/sqlite/lib/src/database.dart b/samples/ffi/sqlite/lib/src/database.dart
index 2cd4316..be2b7ef 100644
--- a/samples/ffi/sqlite/lib/src/database.dart
+++ b/samples/ffi/sqlite/lib/src/database.dart
@@ -5,6 +5,8 @@
 import "dart:collection";
 import "dart:ffi";
 
+import "package:ffi/ffi.dart";
+
 import "bindings/bindings.dart";
 
 import "bindings/types.dart" as types;
@@ -12,7 +14,6 @@
 
 import "bindings/constants.dart";
 import "collections/closable_iterator.dart";
-import "ffi/utf8.dart";
 
 /// [Database] represents an open connection to a SQLite database.
 ///
@@ -26,13 +27,13 @@
   /// Open a database located at the file [path].
   Database(String path,
       [int flags = Flags.SQLITE_OPEN_READWRITE | Flags.SQLITE_OPEN_CREATE]) {
-    Pointer<Pointer<types.Database>> dbOut = Pointer.allocate();
-    final pathC = Utf8.allocate(path);
+    Pointer<Pointer<types.Database>> dbOut = allocate();
+    final pathC = Utf8.toUtf8(path);
     final int resultCode =
-        bindings.sqlite3_open_v2(pathC, dbOut, flags, Pointer.fromAddress(0));
-    _database = dbOut.load();
-    dbOut.free();
-    pathC.free();
+        bindings.sqlite3_open_v2(pathC, dbOut, flags, nullptr);
+    _database = dbOut.value;
+    free(dbOut);
+    free(pathC);
 
     if (resultCode == Errors.SQLITE_OK) {
       _open = true;
@@ -62,13 +63,13 @@
 
   /// Execute a query, discarding any returned rows.
   void execute(String query) {
-    Pointer<Pointer<Statement>> statementOut = Pointer.allocate();
-    Pointer<Utf8> queryC = Utf8.allocate(query);
+    Pointer<Pointer<Statement>> statementOut = allocate();
+    Pointer<Utf8> queryC = Utf8.toUtf8(query);
     int resultCode = bindings.sqlite3_prepare_v2(
-        _database, queryC, -1, statementOut, Pointer.fromAddress(0));
-    Pointer<Statement> statement = statementOut.load();
-    statementOut.free();
-    queryC.free();
+        _database, queryC, -1, statementOut, nullptr);
+    Pointer<Statement> statement = statementOut.value;
+    free(statementOut);
+    free(queryC);
 
     while (resultCode == Errors.SQLITE_ROW || resultCode == Errors.SQLITE_OK) {
       resultCode = bindings.sqlite3_step(statement);
@@ -81,13 +82,13 @@
 
   /// Evaluate a query and return the resulting rows as an iterable.
   Result query(String query) {
-    Pointer<Pointer<Statement>> statementOut = Pointer.allocate();
-    Pointer<Utf8> queryC = Utf8.allocate(query);
+    Pointer<Pointer<Statement>> statementOut = allocate();
+    Pointer<Utf8> queryC = Utf8.toUtf8(query);
     int resultCode = bindings.sqlite3_prepare_v2(
-        _database, queryC, -1, statementOut, Pointer.fromAddress(0));
-    Pointer<Statement> statement = statementOut.load();
-    statementOut.free();
-    queryC.free();
+        _database, queryC, -1, statementOut, nullptr);
+    Pointer<Statement> statement = statementOut.value;
+    free(statementOut);
+    free(queryC);
 
     if (resultCode != Errors.SQLITE_OK) {
       bindings.sqlite3_finalize(statement);
@@ -98,7 +99,7 @@
     int columnCount = bindings.sqlite3_column_count(statement);
     for (int i = 0; i < columnCount; i++) {
       String columnName =
-          bindings.sqlite3_column_name(statement, i).load<Utf8>().toString();
+          bindings.sqlite3_column_name(statement, i).ref.toString();
       columnIndices[columnName] = i;
     }
 
@@ -106,13 +107,12 @@
   }
 
   SQLiteException _loadError([int errorCode]) {
-    String errorMessage =
-        bindings.sqlite3_errmsg(_database).load<Utf8>().toString();
+    String errorMessage = bindings.sqlite3_errmsg(_database).ref.toString();
     if (errorCode == null) {
       return SQLiteException(errorMessage);
     }
     String errorCodeExplanation =
-        bindings.sqlite3_errstr(errorCode).load<Utf8>().toString();
+        bindings.sqlite3_errstr(errorCode).ref.toString();
     return SQLiteException(
         "$errorMessage (Code $errorCode: $errorCodeExplanation)");
   }
@@ -214,7 +214,7 @@
     } else {
       dynamicType = _typeFromText(bindings
           .sqlite3_column_decltype(_statement, columnIndex)
-          .load<Utf8>()
+          .ref
           .toString());
     }
 
@@ -251,10 +251,7 @@
   /// Reads column [columnIndex] and converts to [Type.Text] if not text.
   String readColumnByIndexAsText(int columnIndex) {
     _checkIsCurrentRow();
-    return bindings
-        .sqlite3_column_text(_statement, columnIndex)
-        .load<Utf8>()
-        .toString();
+    return bindings.sqlite3_column_text(_statement, columnIndex).ref.toString();
   }
 
   void _checkIsCurrentRow() {
diff --git a/samples/ffi/sqlite/lib/src/ffi/arena.dart b/samples/ffi/sqlite/lib/src/ffi/arena.dart
index 2e19d55..d01b64f 100644
--- a/samples/ffi/sqlite/lib/src/ffi/arena.dart
+++ b/samples/ffi/sqlite/lib/src/ffi/arena.dart
@@ -5,6 +5,8 @@
 import "dart:async";
 import "dart:ffi";
 
+import 'package:ffi/ffi.dart';
+
 /// [Arena] manages allocated C memory.
 ///
 /// Arenas are zoned.
@@ -22,7 +24,7 @@
   /// Frees all memory pointed to by [Pointer]s in this arena.
   void finalize() {
     for (final ptr in _allocations) {
-      ptr.free();
+      free(ptr);
     }
   }
 
diff --git a/samples/ffi/sqlite/lib/src/ffi/utf8.dart b/samples/ffi/sqlite/lib/src/ffi/utf8.dart
deleted file mode 100644
index 12a04bb..0000000
--- a/samples/ffi/sqlite/lib/src/ffi/utf8.dart
+++ /dev/null
@@ -1,48 +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 "dart:convert";
-import "dart:ffi";
-
-import "arena.dart";
-
-/// Represents a String in C memory, managed by an [Arena].
-class Utf8 extends Struct<Utf8> {
-  @Uint8()
-  int char;
-
-  /// Allocates a [CString] in the current [Arena] and populates it with
-  /// [dartStr].
-  static Pointer<Utf8> fromString(String dartStr) =>
-      Utf8.fromStringArena(Arena.current(), dartStr);
-
-  /// Allocates a [CString] in [arena] and populates it with [dartStr].
-  static Pointer<Utf8> fromStringArena(Arena arena, String dartStr) =>
-      arena.scoped(allocate(dartStr));
-
-  /// Allocate a [CString] not managed in and populates it with [dartStr].
-  ///
-  /// This [CString] is not managed by an [Arena]. Please ensure to [free] the
-  /// memory manually!
-  static Pointer<Utf8> allocate(String dartStr) {
-    List<int> units = Utf8Encoder().convert(dartStr);
-    Pointer<Utf8> str = Pointer.allocate(count: units.length + 1);
-    for (int i = 0; i < units.length; ++i) {
-      str.elementAt(i).load<Utf8>().char = units[i];
-    }
-    str.elementAt(units.length).load<Utf8>().char = 0;
-    return str.cast();
-  }
-
-  /// Read the string for C memory into Dart.
-  String toString() {
-    final str = addressOf;
-    if (str == nullptr) return null;
-    int len = 0;
-    while (str.elementAt(++len).load<Utf8>().char != 0);
-    List<int> units = List(len);
-    for (int i = 0; i < len; ++i) units[i] = str.elementAt(i).load<Utf8>().char;
-    return Utf8Decoder().convert(units);
-  }
-}
diff --git a/samples/ffi/sqlite/pubspec.yaml b/samples/ffi/sqlite/pubspec.yaml
index 8b0136c..04a5fc2 100644
--- a/samples/ffi/sqlite/pubspec.yaml
+++ b/samples/ffi/sqlite/pubspec.yaml
@@ -5,5 +5,8 @@
 author: Daco Harkes <dacoharkes@google.com>, Samir Jindel <sjindel@google.com>
 environment:
   sdk: '>=2.1.0 <3.0.0'
+dependencies:
+  ffi:
+    path: ../../../third_party/pkg/ffi
 dev_dependencies:
-  test: ^1.5.3
\ No newline at end of file
+  test: ^1.5.3
diff --git a/samples/ffi/sqlite/test/sqlite_test.dart b/samples/ffi/sqlite/test/sqlite_test.dart
index 0fd2b6a..78fa39e 100644
--- a/samples/ffi/sqlite/test/sqlite_test.dart
+++ b/samples/ffi/sqlite/test/sqlite_test.dart
@@ -4,13 +4,16 @@
 
 // VMOptions=--optimization-counter-threshold=5
 
+import "dart:ffi";
+import "package:ffi/ffi.dart";
 import "package:test/test.dart";
 
 import '../lib/sqlite.dart';
-import '../lib/src/ffi/utf8.dart';
 
 void main() {
   test("sqlite integration test", () {
+    // TODO(dacoharkes): Put the database relative to this file,
+    // instead of where the script was invoked from.
     Database d = Database("test.db");
     d.execute("drop table if exists Cookies;");
     d.execute("""
@@ -164,8 +167,8 @@
   });
   test("Utf8 unit test", () {
     final String test = 'Hasta Mañana';
-    final medium = Utf8.allocate(test);
-    expect(test, medium.load<Utf8>().toString());
-    medium.free();
+    final medium = Utf8.toUtf8(test);
+    expect(test, medium.ref.toString());
+    free(medium);
   });
 }
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index 3a2e18e..3101029 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -35,7 +35,7 @@
 # ......dartaotruntime or dartaotruntime.exe (executable)
 # ......dartdoc
 # ......dartfmt
-# ......dart2aot
+# ......dart2native
 # ......dart2js
 # ......dartanalyzer
 # ......dartdevc
@@ -51,11 +51,16 @@
 # ........gen_kernel.dart.snapshot
 # ........kernel_worker.dart.snapshot
 # ........pub.dart.snapshot
-#.........resources/
-#...........dartdoc/
-#..............packages
-#.............resources/
-#.............templates/
+# ......resources/
+# ........dartdoc/
+# ...........packages
+# ..........resources/
+# ..........templates/
+# ......model/
+# ........lexeme/
+# ..........idx2word.json
+# ..........model.tflite
+# ..........word2idx.json
 # ....include/
 # ......dart_api.h
 # ......dart_native_api.h
@@ -63,13 +68,13 @@
 # ....lib/
 # ......libraries.json
 # ......_internal/
-#.........strong.sum
-#.........dart2js_platform.dill
-#.........dart2js_server_platform.dill
-#.........dart2js_platform_strong.dill
-#.........dart2js_server_platform_strong.dill
-#.........vm_platform_strong.dill
-#.........dev_compiler/
+# ........strong.sum
+# ........dart2js_platform.dill
+# ........dart2js_server_platform.dill
+# ........dart2js_platform_strong.dill
+# ........dart2js_server_platform_strong.dill
+# ........vm_platform_strong.dill
+# ........dev_compiler/
 # ......async/
 # ......collection/
 # ......convert/
@@ -86,11 +91,6 @@
 # ......typed_data/
 # ......wasm/
 # ......api_readme.md
-# ....model/
-# ......lexeme/
-# ........idx2word.json
-# ........model.tflite
-# ........word2idx.json
 
 # Scripts that go under bin/
 _platform_sdk_scripts = [
@@ -311,7 +311,7 @@
         ":copy_libraries",
       ]
       source = "../pkg/analysis_server/language_model"
-      dest = "$root_out_dir/dart-sdk/model"
+      dest = "$root_out_dir/dart-sdk/bin/model"
       ignore_patterns = "{}"
     },
     {
@@ -435,19 +435,6 @@
   ]
 }
 
-copy("copy_dart2aot") {
-  ext = ""
-  if (is_win) {
-    ext = ".bat"
-  }
-  sources = [
-    "bin/dart2aot$ext",
-  ]
-  outputs = [
-    "$root_out_dir/dart-sdk/bin/{{source_file_part}}",
-  ]
-}
-
 copy("copy_dart2native") {
   deps = [
     ":copy_gen_kernel_snapshot",
diff --git a/sdk/bin/dart2aot b/sdk/bin/dart2aot
deleted file mode 100755
index 9390db6..0000000
--- a/sdk/bin/dart2aot
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/usr/bin/env bash
-# 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.
-
-# Script for generating AOT snapshot in two steps:
-# - Compilation to kernel with additional AOT specific transformations.
-# - Compilation of kernel into snapshot using gen_snapshot.
-
-# Parse incoming arguments and extract the value of --packages option if any
-# was passed. Split options (--xyz) and non-options into two separate arrays.
-# All options will be passed to gen_snapshot, while --packages will be
-# passed to the CFE (Common Front-End).
-
-set -e
-
-OPTIONS=()
-GEN_KERNEL_OPTIONS=()
-PACKAGES=
-BUILD_ELF=0
-
-ARGV=()
-for arg in "$@"; do
-  case $arg in
-    --packages=*)
-    PACKAGES="$arg"
-    ;;
-    --enable-asserts)
-    GEN_KERNEL_OPTIONS+=("$arg")
-    OPTIONS+=("$arg")
-    ;;
-    --tfa | \
-    --no-tfa | \
-    -D* )
-    GEN_KERNEL_OPTIONS+=("$arg")
-    ;;
-    --build-elf)
-    BUILD_ELF=1
-    ;;
-    --*)
-    OPTIONS+=("$arg")
-    ;;
-    *)
-    ARGV+=("$arg")
-    ;;
-  esac
-done
-
-if [ "${#ARGV[@]}" -ne 2 ]; then
-    echo "Usage: $0 [options] <dart-source-file> <dart-aot-file>"
-    echo ""
-    echo "Dart AOT (ahead-of-time) compile Dart source code into native machine code."
-    exit 1
-fi
-
-SOURCE_FILE="${ARGV[0]}"
-SNAPSHOT_FILE="${ARGV[1]}"
-
-if [ $BUILD_ELF -eq 1 ]; then
-  GEN_SNAPSHOT_OPTION="--snapshot-kind=app-aot-assembly"
-  GEN_SNAPSHOT_FILENAME="--assembly=${SNAPSHOT_FILE}.S"
-else
-  GEN_SNAPSHOT_OPTION="--snapshot-kind=app-aot-blobs"
-  GEN_SNAPSHOT_FILENAME="--blobs_container_filename=${SNAPSHOT_FILE}"
-fi
-
-function follow_links() {
-  file="$1"
-  while [ -h "$file" ]; do
-    # On Mac OS, readlink -f doesn't work.
-    file="$(readlink "$file")"
-  done
-  echo "$file"
-}
-
-# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
-PROG_NAME="$(follow_links "$BASH_SOURCE")"
-
-# Handle the case where dart-sdk/bin has been symlinked to.
-BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
-
-SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
-
-DART="$BIN_DIR/dart"
-GEN_SNAPSHOT="$BIN_DIR/utils/gen_snapshot"
-
-SNAPSHOT_DIR="$BIN_DIR/snapshots"
-SNAPSHOT="$SNAPSHOT_DIR/gen_kernel.dart.snapshot"
-
-# Step 1: Generate Kernel binary from the input Dart source.
-"$DART"                                                                        \
-     "${SNAPSHOT}"                                                             \
-     --platform "${SDK_DIR}/lib/_internal/vm_platform_strong.dill"             \
-     --aot                                                                     \
-     -Ddart.vm.product=true                                                    \
-     "${GEN_KERNEL_OPTIONS[@]}"                                                \
-     $PACKAGES                                                                 \
-     -o "$SNAPSHOT_FILE.dill"                                                  \
-     "$SOURCE_FILE"
-
-# Step 2: Generate snapshot from the Kernel binary.
-"$GEN_SNAPSHOT"                                                                \
-     "$GEN_SNAPSHOT_OPTION"                                                    \
-     "$GEN_SNAPSHOT_FILENAME"                                                  \
-     "${OPTIONS[@]}"                                                           \
-     "$SNAPSHOT_FILE.dill"
-
-# Step 3: Assemble the assembly file into an ELF object.
-if [ $BUILD_ELF -eq 1 ]; then
-    gcc -shared -o "$SNAPSHOT_FILE" "${SNAPSHOT_FILE}.S"
-fi
diff --git a/sdk/bin/dart2aot.bat b/sdk/bin/dart2aot.bat
deleted file mode 100644
index 321e867..0000000
--- a/sdk/bin/dart2aot.bat
+++ /dev/null
@@ -1,58 +0,0 @@
-@echo off
-REM Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
-REM for details. All rights reserved. Use of this source code is governed by a
-REM BSD-style license that can be found in the LICENSE file.
-
-setlocal
-rem Handle the case where dart-sdk/bin has been symlinked to.
-set DIR_NAME_WITH_SLASH=%~dp0
-set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
-call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
-rem Get rid of surrounding quotes.
-for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
-
-rem Get absolute full name for SDK_DIR.
-for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
-
-rem Remove trailing backslash if there is one
-IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
-
-rem Get absolute full name for DART_ROOT.
-for %%i in ("%SDK_DIR%\..\") do set DART_ROOT=%%~fi
-
-rem Remove trailing backslash if there is one
-if %DART_ROOT:~-1%==\ set DART_ROOT=%DART_ROOT:~0,-1%
-
-set DART=%BIN_DIR%\dart.exe
-set GEN_KERNEL=%BIN_DIR%\snapshots\gen_kernel.dart.snapshot
-set VM_PLATFORM_STRONG=%SDK_DIR%\lib\_internal\vm_platform_strong.dill
-set GEN_SNAPSHOT=%BIN_DIR%\utils\gen_snapshot.exe
-
-set SOURCE_FILE=%1
-set SNAPSHOT_FILE=%2
-set GEN_SNAPSHOT_OPTION=--snapshot-kind=app-aot-blobs
-set GEN_SNAPSHOT_FILENAME=--blobs_container_filename=%SNAPSHOT_FILE%
-
-REM Step 1: Generate Kernel binary from the input Dart source.
-%DART% %GEN_KERNEL% --platform %VM_PLATFORM_STRONG% --aot -Ddart.vm.product=true -o %SNAPSHOT_FILE%.dill %SOURCE_FILE%
-
-REM Step 2: Generate snapshot from the Kernel binary.
-%GEN_SNAPSHOT% %GEN_SNAPSHOT_OPTION% %GEN_SNAPSHOT_FILENAME% %SNAPSHOT_FILE%.dill
-
-endlocal
-
-exit /b %errorlevel%
-
-:follow_links
-setlocal
-for %%i in (%1) do set result=%%~fi
-set current=
-for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
-                                             ^| %SystemRoot%\System32\find.exe ">     %~n1 [" 2^>nul`) do (
-  set current=%%i
-)
-if not "%current%"=="" call :follow_links "%current%", result
-endlocal & set %~2=%result%
-goto :eof
-
-:end
diff --git a/sdk/bin/dartfix b/sdk/bin/dartfix
new file mode 100755
index 0000000..bbeb80d
--- /dev/null
+++ b/sdk/bin/dartfix
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+# 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.
+
+# Run dartfix.dart on the Dart VM. This script assumes the Dart SDK's
+# directory structure.
+
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+
+SNAPSHOT="$BIN_DIR/snapshots/dartfix.dart.snapshot"
+
+# We are running the snapshot in the built SDK.
+DART="$BIN_DIR/dart"
+exec "$DART" "$SNAPSHOT" "$@"
diff --git a/sdk/bin/dartfix.bat b/sdk/bin/dartfix.bat
new file mode 100644
index 0000000..4241694
--- /dev/null
+++ b/sdk/bin/dartfix.bat
@@ -0,0 +1,44 @@
+@echo off
+REM Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+set DART=%BIN_DIR%\dart
+set SNAPSHOT=%BIN_DIR%\snapshots\dartfix.dart.snapshot
+
+"%DART%" "%SNAPSHOT%" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+rem Follow the symbolic links (junctions points) using `dir to determine the
+rem canonical path. Output with a link looks something like this
+rem
+rem 01/03/2013  10:11 PM    <JUNCTION>     abc def
+rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
+rem
+rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
+rem surrounded by right angle bracket and left square bracket. Once we get
+rem the filename, which is name of the link, we recursively follow that.
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+                                             ^| find ">     %~n1 [" 2^>nul`) do (
+  set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
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 746ac61..43e0f08 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart
@@ -1021,9 +1021,7 @@
   static _BigIntImpl _tryParse(String source, {int radix}) {
     if (source == "") return null;
 
-    var re = RegExp(r'^\s*([+-]?)((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$',
-        caseSensitive: false);
-    var match = re.firstMatch(source);
+    var match = _parseRE.firstMatch(source);
     int signIndex = 1;
     int hexIndex = 3;
     int decimalIndex = 4;
@@ -1065,6 +1063,10 @@
         decimalMatch ?? nonDecimalMatch ?? hexMatch, radix, isNegative);
   }
 
+  static RegExp _parseRE = RegExp(
+      r'^\s*([+-]?)((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$',
+      caseSensitive: false);
+
   /// Finds the amount significant digits in the provided [digits] array.
   static int _normalize(int used, Uint16List digits) {
     while (used > 0 && digits[used - 1] == 0) used--;
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 f59c330..6f07c07 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
@@ -19,7 +19,7 @@
 ///
 ///   - All other types are represented as instances of class [DartType],
 ///     defined in this module.
-///     - Dynamic, Void, and Bottom are singleton instances of sentinal
+///     - Dynamic, Void, and Bottom are singleton instances of sentinel
 ///       classes.
 ///     - Function types are instances of subclasses of AbstractFunctionType.
 ///
@@ -898,6 +898,8 @@
     if (${_isFutureOr(t2)}) {
       let t2TypeArg = ${getGenericArgs(t2)}[0];
       // FutureOr<A> <: FutureOr<B> iff A <: B
+      // TODO(nshahan): Proven to not actually be true and needs cleanup.
+      // https://github.com/dart-lang/sdk/issues/38818
       return $_isSubtype(t1TypeArg, t2TypeArg);
     }
 
diff --git a/sdk/lib/_internal/js_runtime/interceptors_sources.gni b/sdk/lib/_internal/js_runtime/interceptors_sources.gni
new file mode 100644
index 0000000..b3a8760
--- /dev/null
+++ b/sdk/lib/_internal/js_runtime/interceptors_sources.gni
@@ -0,0 +1,5 @@
+# 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.
+
+interceptors_sdk_sources = [ "lib/interceptors.dart" ]
diff --git a/sdk/lib/_internal/js_runtime/lib/core_patch.dart b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
index c655fc2..ec8dbc4 100644
--- a/sdk/lib/_internal/js_runtime/lib/core_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
@@ -1071,9 +1071,7 @@
   static _BigIntImpl _tryParse(String source, {int radix}) {
     if (source == "") return null;
 
-    var re = new RegExp(r'^\s*([+-]?)((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$',
-        caseSensitive: false);
-    var match = re.firstMatch(source);
+    var match = _parseRE.firstMatch(source);
     int signIndex = 1;
     int hexIndex = 3;
     int decimalIndex = 4;
@@ -1115,6 +1113,10 @@
         decimalMatch ?? nonDecimalMatch ?? hexMatch, radix, isNegative);
   }
 
+  static RegExp _parseRE = RegExp(
+      r'^\s*([+-]?)((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$',
+      caseSensitive: false);
+
   /// Finds the amount significant digits in the provided [digits] array.
   static int _normalize(int used, Uint16List digits) {
     while (used > 0 && digits[used - 1] == 0) used--;
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index a1187f6..5b7b6aa 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -2280,7 +2280,8 @@
     if (JS('bool', 'typeof # == "string"', functionType)) {
       // A recipe to evaluate against the instance type.
       if (isStatic) {
-        throw 'TODO: Recipe for static tearoff.';
+        // TODO(sra): Recipe for static tearoff.
+        throw 'Cannot compute signature for static tearoff.';
       }
       var typeEvalMethod = isIntercepted
           ? RAW_DART_FUNCTION_REF(BoundClosure.evalRecipeIntercepted)
diff --git a/sdk/lib/_internal/js_runtime/lib/js_rti.dart b/sdk/lib/_internal/js_runtime/lib/js_rti.dart
index f581bd8..762cd88 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_rti.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_rti.dart
@@ -706,13 +706,10 @@
     return false;
   }
 
-  // Generic function type parameters must match exactly, which would have
-  // exited earlier. The de Bruijn indexing ensures the representation as a
-  // small number can be used for type comparison.
   if (isGenericFunctionTypeParameter(s)) {
-    // TODO(sra): Use the bound of the type variable.
-    return false;
+    return _isSubtype(getIndex(sEnv, s), sEnv, t, tEnv);
   }
+
   if (isGenericFunctionTypeParameter(t)) return false;
 
   if (isNullType(s)) return true;
@@ -809,9 +806,8 @@
     if (sGenericParameters != tGenericParameters) return false;
     // TODO(sra): Compare bounds, which should be 'equal' trees due to the de
     // Bruijn numbering of type parameters.
-    // TODO(sra): Extend [sEnv] and [tEnv] with bindings for the [s] and [t]
-    // type parameters to enable checking the bound against non-type-parameter
-    // terms.
+    sEnv = sEnv == null ? sBounds : concat(sBounds, sEnv);
+    tEnv = tEnv == null ? tBounds : concat(tBounds, tEnv);
   } else if (hasField(t, genericBoundsTag)) {
     return false;
   }
@@ -1127,3 +1123,5 @@
         rti,
         JS_BUILTIN(
             'depends:none;effects:none;', JsBuiltin.dartObjectConstructor));
+
+concat(Object a1, Object a2) => JS('JSArray', '#.concat(#)', a1, a2);
diff --git a/sdk/lib/_internal/js_runtime/lib/rti.dart b/sdk/lib/_internal/js_runtime/lib/rti.dart
index 6c6729a..b3890bd 100644
--- a/sdk/lib/_internal/js_runtime/lib/rti.dart
+++ b/sdk/lib/_internal/js_runtime/lib/rti.dart
@@ -2143,11 +2143,6 @@
     return false;
   }
 
-  // Generic function type parameters must match exactly, which would have
-  // exited earlier.
-  if (isGenericFunctionTypeParameter(s)) return false;
-  if (isGenericFunctionTypeParameter(t)) return false;
-
   if (isNullType(s)) return true;
 
   if (isFutureOrType(t)) {
@@ -2169,6 +2164,18 @@
     }
   }
 
+  // If [s] and [t] are both generic function type parameters, they must be
+  // equal (as de Bruijn indices). This case is taken care of by the reflexivity
+  // check above, so it suffices to check that B <: [t] where B is the bound of
+  // [s].
+  if (isGenericFunctionTypeParameter(s)) {
+    int index = Rti._getGenericFunctionParameterIndex(s);
+    Rti bound = _castToRti(_Utils.arrayAt(sEnv, index));
+    return _isSubtype(universe, bound, sEnv, t, tEnv);
+  }
+
+  if (isGenericFunctionTypeParameter(t)) return false;
+
   // TODO(fishythefish): Disallow JavaScriptFunction as a subtype of function
   // types using features inaccessible from JavaScript.
 
@@ -2200,9 +2207,9 @@
   var sBounds = Rti._getGenericFunctionBounds(s);
   var tBounds = Rti._getGenericFunctionBounds(t);
   if (!typesEqual(sBounds, tBounds)) return false;
-  // TODO(fishythefish): Extend [sEnv] and [tEnv] with bindings for the [s]
-  // and [t] type parameters to enable checking the bound against
-  // non-type-parameter terms.
+
+  sEnv = sEnv == null ? sBounds : _Utils.arrayConcat(sBounds, sEnv);
+  tEnv = tEnv == null ? tBounds : _Utils.arrayConcat(tBounds, tEnv);
 
   return _isFunctionSubtype(universe, Rti._getGenericFunctionBase(s), sEnv,
       Rti._getGenericFunctionBase(t), tEnv);
diff --git a/sdk/lib/_internal/vm/bin/file_patch.dart b/sdk/lib/_internal/vm/bin/file_patch.dart
index 338a260..57cf8fd 100644
--- a/sdk/lib/_internal/vm/bin/file_patch.dart
+++ b/sdk/lib/_internal/vm/bin/file_patch.dart
@@ -294,6 +294,19 @@
         }
       } else if (event == RawSocketEvent.closed) {
       } else if (event == RawSocketEvent.readClosed) {
+        // If Directory watcher buffer overflows, it will send an readClosed event.
+        // Normal closing will cancel stream subscription so that path is
+        // no longer being watched, not present in _idMap.
+        if (_idMap.containsKey(pathId)) {
+          var path = _pathFromPathId(pathId).path;
+          _idMap.remove(pathId);
+          if (_idMap.isEmpty && _id != null) {
+            _closeWatcher(_id);
+            _id = null;
+          }
+          throw FileSystemException(
+              'Directory watcher closed unexpectedly', path);
+        }
       } else {
         assert(false);
       }
diff --git a/sdk/lib/_internal/vm/lib/bigint_patch.dart b/sdk/lib/_internal/vm/lib/bigint_patch.dart
index 5bfda0c..e49305d 100644
--- a/sdk/lib/_internal/vm/lib/bigint_patch.dart
+++ b/sdk/lib/_internal/vm/lib/bigint_patch.dart
@@ -269,9 +269,7 @@
   static _BigIntImpl _tryParse(String source, {int radix}) {
     if (source == "") return null;
 
-    var re = new RegExp(r'^\s*([+-]?)((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$',
-        caseSensitive: false);
-    var match = re.firstMatch(source);
+    var match = _parseRE.firstMatch(source);
     int signIndex = 1;
     int hexIndex = 3;
     int decimalIndex = 4;
@@ -313,6 +311,10 @@
         decimalMatch ?? nonDecimalMatch ?? hexMatch, radix, isNegative);
   }
 
+  static RegExp _parseRE = RegExp(
+      r'^\s*([+-]?)((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$',
+      caseSensitive: false);
+
   /// Finds the amount significant digits in the provided [digits] array.
   static int _normalize(int used, Uint32List digits) {
     while (used > 0 && digits[used - 1] == 0) used--;
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 c92dc1b..d07645d 100644
--- a/sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart
@@ -5,7 +5,7 @@
 // All imports must be in all FFI patch files to not depend on the order
 // the patches are applied.
 import "dart:_internal" show patch;
-import 'dart:typed_data' show TypedData;
+import 'dart:typed_data';
 
 DynamicLibrary _open(String name) native "Ffi_dl_open";
 DynamicLibrary _processLibrary() native "Ffi_dl_processLibrary";
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 cd229de2..dcd76ed 100644
--- a/sdk/lib/_internal/vm/lib/ffi_native_type_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_native_type_patch.dart
@@ -5,7 +5,7 @@
 // All imports must be in all FFI patch files to not depend on the order
 // the patches are applied.
 import "dart:_internal" show patch;
-import 'dart:typed_data' show TypedData;
+import 'dart:typed_data';
 
 // NativeType is not private, because it is used in type arguments.
 // NativeType is abstract because it not used with const constructors in
diff --git a/sdk/lib/_internal/vm/lib/ffi_patch.dart b/sdk/lib/_internal/vm/lib/ffi_patch.dart
index 089f0c9..69e6b20 100644
--- a/sdk/lib/_internal/vm/lib/ffi_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_patch.dart
@@ -5,13 +5,39 @@
 // All imports must be in all FFI patch files to not depend on the order
 // the patches are applied.
 import "dart:_internal" show patch;
-import 'dart:typed_data' show TypedData;
+import 'dart:typed_data';
+
+const Map<Type, int> _knownSizes = {
+  Int8: 1,
+  Uint8: 1,
+  Int16: 2,
+  Uint16: 2,
+  Int32: 4,
+  Uint32: 4,
+  Int64: 8,
+  Uint64: 8,
+  Float: 4,
+  Double: 8,
+};
+
+final int _intPtrSize = [8, 4, 4][_abi()];
 
 @patch
-int sizeOf<T extends NativeType>() native "Ffi_sizeOf";
+int sizeOf<T extends NativeType>() {
+  // This is not super fast, but it is faster than a runtime entry.
+  // Hot loops with elementAt().load() do not use this sizeOf, elementAt is
+  // optimized per NativeType statically to prevent use of sizeOf at runtime.
+  final int knownSize = _knownSizes[T];
+  if (knownSize != null) return knownSize;
+  if (T == IntPtr) return _intPtrSize;
+  if (T == Pointer) return _intPtrSize;
+  // For structs we fall back to a runtime entry.
+  return _sizeOf<T>();
+}
 
-Pointer<T> _allocate<T extends NativeType>(int count) native "Ffi_allocate";
+int _sizeOf<T extends NativeType>() native "Ffi_sizeOf";
 
+// Implemented in the method recognizer, bytecode interpreter uses runtime.
 Pointer<T> _fromAddress<T extends NativeType>(int ptr) native "Ffi_fromAddress";
 
 // The real implementation of this function (for interface calls) lives in
@@ -46,9 +72,6 @@
 @pragma("vm:entry-point")
 class Pointer<T extends NativeType> {
   @patch
-  factory Pointer.allocate({int count: 1}) => _allocate<T>(count);
-
-  @patch
   factory Pointer.fromAddress(int ptr) => _fromAddress(ptr);
 
   // All static calls to this method are replaced by the FE into
@@ -64,50 +87,358 @@
         "Pointer.fromFunction cannot be called dynamically.");
   }
 
-  // TODO(sjindel): When NNBD is available, we should change `value` to be
-  // non-null.
-  @patch
-  void store(Object value) native "Ffi_store";
-
-  @patch
-  R load<R>() native "Ffi_load";
-
+  // Implemented in the method recognizer, bytecode interpreter uses runtime.
   @patch
   int get address native "Ffi_address";
 
-  // Note this could also be implmented without an extra native as offsetBy
-  // (elementSize()*index). This would be 2 native calls rather than one. What
-  // would be better?
+  // For statically known types, this is rewired.
+  // (Method sizeOf is slow, see notes above.)
   @patch
-  Pointer<T> elementAt(int index) native "Ffi_elementAt";
+  Pointer<T> elementAt(int index) =>
+      Pointer.fromAddress(address + sizeOf<T>() * index);
 
-  // Note this could also be implmented without an extra  native as
-  // fromAddress(address). This would be 2 native calls rather than one.
-  // What would be better?
   @patch
-  Pointer<T> offsetBy(int offsetInBytes) native "Ffi_offsetBy";
+  Pointer<T> _offsetBy(int offsetInBytes) =>
+      Pointer.fromAddress(address + offsetInBytes);
 
-  // Note this could also be implemented without an extra native as
-  // fromAddress(address). This would be 2 native calls rather than one.
-  // What would be better?
   @patch
-  Pointer<U> cast<U extends NativeType>() native "Ffi_cast";
+  Pointer<U> cast<U extends NativeType>() => Pointer.fromAddress(address);
 
   @patch
   R asFunction<R extends Function>() {
     throw UnsupportedError("Pointer.asFunction cannot be called dynamically.");
   }
-
-  @patch
-  void free() native "Ffi_free";
-
-  @patch
-  TypedData asExternalTypedData({int count: 1}) =>
-      _asExternalTypedData(this, count);
 }
 
-// Returns the ABI used for size and alignment calculations.
-// See pkg/vm/lib/transformations/ffi.dart.
+/// Returns an integer encoding the ABI used for size and alignment
+/// calculations. See pkg/vm/lib/transformations/ffi.dart.
 @pragma('vm:prefer-inline')
 int _abi()
     native "Recognized method: method is directly interpreted by the bytecode interpreter or IR graph is built in the flow graph builder.";
+
+// The following functions are implemented in the method recognizer, but the
+// bytecode interpreter uses native entries.
+//
+// TODO(38172): Since these are not inlined (force optimize), they force
+// allocating a Pointer with in elementAt/offsetBy. Allocating these pointers
+// and GCing new spaces takes a lot of the benchmark time. The next speedup is
+// getting rid of these allocations by inlining these functions.
+//
+// TODO(37773): Change _loadInt8 etc to take an index.
+int _loadInt8(Pointer<Int8> pointer, int index) native "Ffi_loadInt8";
+
+int _loadInt16(Pointer<Int16> pointer, int index) native "Ffi_loadInt16";
+
+int _loadInt32(Pointer<Int32> pointer, int index) native "Ffi_loadInt32";
+
+int _loadInt64(Pointer<Int64> pointer, int index) native "Ffi_loadInt64";
+
+int _loadUint8(Pointer<Uint8> pointer, int index) native "Ffi_loadUint8";
+
+int _loadUint16(Pointer<Uint16> pointer, int index) native "Ffi_loadUint16";
+
+int _loadUint32(Pointer<Uint32> pointer, int index) native "Ffi_loadUint32";
+
+int _loadUint64(Pointer<Uint64> pointer, int index) native "Ffi_loadUint64";
+
+int _loadIntPtr(Pointer<IntPtr> pointer, int index) native "Ffi_loadIntPtr";
+
+double _loadFloat(Pointer<Float> pointer, int index) native "Ffi_loadFloat";
+
+double _loadDouble(Pointer<Double> pointer, int index) native "Ffi_loadDouble";
+
+Pointer<S> _loadPointer<S extends NativeType>(
+    Pointer<Pointer<S>> pointer, int index) native "Ffi_loadPointer";
+
+S _loadStruct<S extends Struct>(Pointer<S> pointer, int index)
+    native "Ffi_loadStruct";
+
+void _storeInt8(Pointer<Int8> pointer, int index, int value)
+    native "Ffi_storeInt8";
+
+void _storeInt16(Pointer<Int16> pointer, int index, int value)
+    native "Ffi_storeInt16";
+
+void _storeInt32(Pointer<Int32> pointer, int index, int value)
+    native "Ffi_storeInt32";
+
+void _storeInt64(Pointer<Int64> pointer, int index, int value)
+    native "Ffi_storeInt64";
+
+void _storeUint8(Pointer<Uint8> pointer, int index, int value)
+    native "Ffi_storeUint8";
+
+void _storeUint16(Pointer<Uint16> pointer, int index, int value)
+    native "Ffi_storeUint16";
+
+void _storeUint32(Pointer<Uint32> pointer, int index, int value)
+    native "Ffi_storeUint32";
+
+void _storeUint64(Pointer<Uint64> pointer, int index, int value)
+    native "Ffi_storeUint64";
+
+void _storeIntPtr(Pointer<IntPtr> pointer, int index, int value)
+    native "Ffi_storeIntPtr";
+
+void _storeFloat(Pointer<Float> pointer, int index, double value)
+    native "Ffi_storeFloat";
+
+void _storeDouble(Pointer<Double> pointer, int index, double value)
+    native "Ffi_storeDouble";
+
+void _storePointer<S extends NativeType>(Pointer<Pointer<S>> pointer, int index,
+    Pointer<S> value) native "Ffi_storePointer";
+
+Pointer<Int8> _elementAtInt8(Pointer<Int8> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + 1 * index);
+
+Pointer<Int16> _elementAtInt16(Pointer<Int16> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + 2 * index);
+
+Pointer<Int32> _elementAtInt32(Pointer<Int32> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + 4 * index);
+
+Pointer<Int64> _elementAtInt64(Pointer<Int64> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + 8 * index);
+
+Pointer<Uint8> _elementAtUint8(Pointer<Uint8> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + 1 * index);
+
+Pointer<Uint16> _elementAtUint16(Pointer<Uint16> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + 2 * index);
+
+Pointer<Uint32> _elementAtUint32(Pointer<Uint32> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + 4 * index);
+
+Pointer<Uint64> _elementAtUint64(Pointer<Uint64> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + 8 * index);
+
+Pointer<IntPtr> _elementAtIntPtr(Pointer<IntPtr> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + _intPtrSize * index);
+
+Pointer<Float> _elementAtFloat(Pointer<Float> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + 4 * index);
+
+Pointer<Double> _elementAtDouble(Pointer<Double> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + 8 * index);
+
+Pointer<Pointer<S>> _elementAtPointer<S extends NativeType>(
+        Pointer<Pointer<S>> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + _intPtrSize * index);
+
+//
+// The following code is generated, do not edit by hand.
+//
+// Code generated by `runtime/tools/ffi/sdk_lib_ffi_generator.dart`.
+//
+
+extension Int8Pointer on Pointer<Int8> {
+  @patch
+  int get value => _loadInt8(this, 0);
+
+  @patch
+  set value(int value) => _storeInt8(this, 0, value);
+
+  @patch
+  int operator [](int index) => _loadInt8(this, index);
+
+  @patch
+  operator []=(int index, int value) => _storeInt8(this, index, value);
+
+  @patch
+  Int8List asTypedList(int elements) => _asExternalTypedData(this, elements);
+}
+
+extension Int16Pointer on Pointer<Int16> {
+  @patch
+  int get value => _loadInt16(this, 0);
+
+  @patch
+  set value(int value) => _storeInt16(this, 0, value);
+
+  @patch
+  int operator [](int index) => _loadInt16(this, index);
+
+  @patch
+  operator []=(int index, int value) => _storeInt16(this, index, value);
+
+  @patch
+  Int16List asTypedList(int elements) => _asExternalTypedData(this, elements);
+}
+
+extension Int32Pointer on Pointer<Int32> {
+  @patch
+  int get value => _loadInt32(this, 0);
+
+  @patch
+  set value(int value) => _storeInt32(this, 0, value);
+
+  @patch
+  int operator [](int index) => _loadInt32(this, index);
+
+  @patch
+  operator []=(int index, int value) => _storeInt32(this, index, value);
+
+  @patch
+  Int32List asTypedList(int elements) => _asExternalTypedData(this, elements);
+}
+
+extension Int64Pointer on Pointer<Int64> {
+  @patch
+  int get value => _loadInt64(this, 0);
+
+  @patch
+  set value(int value) => _storeInt64(this, 0, value);
+
+  @patch
+  int operator [](int index) => _loadInt64(this, index);
+
+  @patch
+  operator []=(int index, int value) => _storeInt64(this, index, value);
+
+  @patch
+  Int64List asTypedList(int elements) => _asExternalTypedData(this, elements);
+}
+
+extension Uint8Pointer on Pointer<Uint8> {
+  @patch
+  int get value => _loadUint8(this, 0);
+
+  @patch
+  set value(int value) => _storeUint8(this, 0, value);
+
+  @patch
+  int operator [](int index) => _loadUint8(this, index);
+
+  @patch
+  operator []=(int index, int value) => _storeUint8(this, index, value);
+
+  @patch
+  Uint8List asTypedList(int elements) => _asExternalTypedData(this, elements);
+}
+
+extension Uint16Pointer on Pointer<Uint16> {
+  @patch
+  int get value => _loadUint16(this, 0);
+
+  @patch
+  set value(int value) => _storeUint16(this, 0, value);
+
+  @patch
+  int operator [](int index) => _loadUint16(this, index);
+
+  @patch
+  operator []=(int index, int value) => _storeUint16(this, index, value);
+
+  @patch
+  Uint16List asTypedList(int elements) => _asExternalTypedData(this, elements);
+}
+
+extension Uint32Pointer on Pointer<Uint32> {
+  @patch
+  int get value => _loadUint32(this, 0);
+
+  @patch
+  set value(int value) => _storeUint32(this, 0, value);
+
+  @patch
+  int operator [](int index) => _loadUint32(this, index);
+
+  @patch
+  operator []=(int index, int value) => _storeUint32(this, index, value);
+
+  @patch
+  Uint32List asTypedList(int elements) => _asExternalTypedData(this, elements);
+}
+
+extension Uint64Pointer on Pointer<Uint64> {
+  @patch
+  int get value => _loadUint64(this, 0);
+
+  @patch
+  set value(int value) => _storeUint64(this, 0, value);
+
+  @patch
+  int operator [](int index) => _loadUint64(this, index);
+
+  @patch
+  operator []=(int index, int value) => _storeUint64(this, index, value);
+
+  @patch
+  Uint64List asTypedList(int elements) => _asExternalTypedData(this, elements);
+}
+
+extension IntPtrPointer on Pointer<IntPtr> {
+  @patch
+  int get value => _loadIntPtr(this, 0);
+
+  @patch
+  set value(int value) => _storeIntPtr(this, 0, value);
+
+  @patch
+  int operator [](int index) => _loadIntPtr(this, index);
+
+  @patch
+  operator []=(int index, int value) => _storeIntPtr(this, index, value);
+}
+
+extension FloatPointer on Pointer<Float> {
+  @patch
+  double get value => _loadFloat(this, 0);
+
+  @patch
+  set value(double value) => _storeFloat(this, 0, value);
+
+  @patch
+  double operator [](int index) => _loadFloat(this, index);
+
+  @patch
+  operator []=(int index, double value) => _storeFloat(this, index, value);
+
+  @patch
+  Float32List asTypedList(int elements) => _asExternalTypedData(this, elements);
+}
+
+extension DoublePointer on Pointer<Double> {
+  @patch
+  double get value => _loadDouble(this, 0);
+
+  @patch
+  set value(double value) => _storeDouble(this, 0, value);
+
+  @patch
+  double operator [](int index) => _loadDouble(this, index);
+
+  @patch
+  operator []=(int index, double value) => _storeDouble(this, index, value);
+
+  @patch
+  Float64List asTypedList(int elements) => _asExternalTypedData(this, elements);
+}
+
+//
+// End of generated code.
+//
+
+extension PointerPointer<T extends NativeType> on Pointer<Pointer<T>> {
+  @patch
+  Pointer<T> get value => _loadPointer(this, 0);
+
+  @patch
+  set value(Pointer<T> value) => _storePointer(this, 0, value);
+
+  @patch
+  Pointer<T> operator [](int index) => _loadPointer(this, index);
+
+  @patch
+  operator []=(int index, Pointer<T> value) =>
+      _storePointer(this, index, value);
+}
+
+extension StructPointer<T extends Struct> on Pointer<T> {
+  @patch
+  T get ref => _loadStruct(this, 0);
+
+  @patch
+  T operator [](int index) => _loadStruct(this, index);
+}
diff --git a/sdk/lib/_internal/vm/lib/mirrors_impl.dart b/sdk/lib/_internal/vm/lib/mirrors_impl.dart
index 013246c..b0231b2 100644
--- a/sdk/lib/_internal/vm/lib/mirrors_impl.dart
+++ b/sdk/lib/_internal/vm/lib/mirrors_impl.dart
@@ -157,6 +157,7 @@
   bool get isExternal => false;
   bool get isRedirectingConstructor => false;
   bool get isAbstract => false;
+  bool get isExtensionMember => false;
 
   bool get isSetter => !isGetter;
   bool get isPrivate => _n(simpleName).startsWith('_');
@@ -193,6 +194,7 @@
   bool get isConst => false;
   bool get isFinal => true;
   bool get isPrivate => false;
+  bool get isExtensionMember => false;
   bool get hasDefaultValue => false;
   InstanceMirror get defaultValue => null;
   SourceLocation get location => null;
@@ -1168,6 +1170,7 @@
   static const kFactoryCtor = 7;
   static const kExternal = 8;
   static const kSynthetic = 9;
+  static const kExtensionMember = 10;
 
   // These offsets much be kept in sync with those in mirrors.h.
   bool get isAbstract => 0 != (_kindFlags & (1 << kAbstract));
@@ -1182,6 +1185,7 @@
   bool get isFactoryConstructor => 0 != (_kindFlags & (1 << kFactoryCtor));
   bool get isExternal => 0 != (_kindFlags & (1 << kExternal));
   bool get isSynthetic => 0 != (_kindFlags & (1 << kSynthetic));
+  bool get isExtensionMember => 0 != (_kindFlags & (1 << kExtensionMember));
 
   static const _operators = const [
     "%", "&", "*", "+", "-", "/", "<", "<<", //
@@ -1281,9 +1285,10 @@
   final bool isStatic;
   final bool isFinal;
   final bool isConst;
+  final bool isExtensionMember;
 
   _VariableMirror._(reflectee, String simpleName, this.owner, this._type,
-      this.isStatic, this.isFinal, this.isConst)
+      this.isStatic, this.isFinal, this.isConst, this.isExtensionMember)
       : super._(reflectee, _s(simpleName));
 
   bool get isTopLevel => owner is LibraryMirror;
@@ -1339,7 +1344,8 @@
             null, // We override the type.
             false, // isStatic does not apply.
             isFinal,
-            false // Not const.
+            false, // Not const.
+            false // Not extension member.
             );
 
   Object _defaultValueReflectee;
diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart
index 911ecff..7c66de1 100644
--- a/sdk/lib/async/zone.dart
+++ b/sdk/lib/async/zone.dart
@@ -229,7 +229,7 @@
  * an existing zone likely created using [Zone.fork].
  *
  * Developers can create a new zone that overrides some of the functionality of
- * an existing zone. For example, custom zones can replace of modify the
+ * an existing zone. For example, custom zones can replace or modify the
  * behavior of `print`, timers, microtasks or how uncaught errors are handled.
  *
  * The [Zone] class is not subclassable, but users can provide custom zones by
diff --git a/sdk/lib/developer/timeline.dart b/sdk/lib/developer/timeline.dart
index 5658e1e..b5c6072 100644
--- a/sdk/lib/developer/timeline.dart
+++ b/sdk/lib/developer/timeline.dart
@@ -190,12 +190,8 @@
 
   /// Create a task with an explicit [taskId]. This is useful if you are
   /// passing a task from one isolate to another.
-  ///
-  /// If [parent] is provided, the parent's task ID is provided as argument
-  /// 'parentId' when [start] is called. In DevTools, this argument will result
-  /// in this [TimelineTask] being linked to the [parent] [TimelineTask].
-  TimelineTask.withTaskId(int taskId, {TimelineTask parent})
-      : _parent = parent,
+  TimelineTask.withTaskId(int taskId)
+      : _parent = null,
         _taskId = taskId {
     ArgumentError.checkNotNull(taskId, 'taskId');
   }
diff --git a/sdk/lib/ffi/annotations.dart b/sdk/lib/ffi/annotations.dart
index d246b56..f68e525 100644
--- a/sdk/lib/ffi/annotations.dart
+++ b/sdk/lib/ffi/annotations.dart
@@ -21,7 +21,7 @@
   /// [Pointer]<T>                         -> [Pointer]<T>
   /// [NativeFunction]<T1 Function(T2, T3) -> S1 Function(S2, S3)
   ///    where DartRepresentationOf(Tn) -> Sn
-  /// T extends Struct<T>                  -> T
+  /// T extends Struct                  -> T
   const DartRepresentationOf(String nativeType);
 }
 
diff --git a/sdk/lib/ffi/ffi.dart b/sdk/lib/ffi/ffi.dart
index a975a13..422788f 100644
--- a/sdk/lib/ffi/ffi.dart
+++ b/sdk/lib/ffi/ffi.dart
@@ -14,7 +14,7 @@
  */
 library dart.ffi;
 
-import 'dart:typed_data' show TypedData;
+import 'dart:typed_data';
 
 part "native_type.dart";
 part "annotations.dart";
@@ -26,18 +26,13 @@
 /// Includes padding and alignment of structs.
 external int sizeOf<T extends NativeType>();
 
-/// Represents a pointer into the native C memory.
-final Pointer<Void> nullptr = Pointer.fromAddress(0);
+/// Represents a pointer into the native C memory corresponding to "NULL", e.g.
+/// a pointer with address 0.
+final Pointer<Null> nullptr = Pointer.fromAddress(0);
 
 /// Represents a pointer into the native C memory. Cannot be extended.
 @pragma("vm:entry-point")
 class Pointer<T extends NativeType> extends NativeType {
-  /// Allocate [count] elements of type [T] on the native heap via malloc() and
-  /// return a pointer to the newly allocated memory.
-  ///
-  /// Note that the memory is uninitialized.
-  external factory Pointer.allocate({int count: 1});
-
   /// Construction from raw integer.
   external factory Pointer.fromAddress(int ptr);
 
@@ -61,20 +56,6 @@
       @DartRepresentationOf("T") Function f,
       [Object exceptionalReturn]);
 
-  /// Store a Dart value into this location.
-  ///
-  /// The [value] is automatically marshalled into its native representation.
-  /// Note that ints which do not fit in [T] are truncated and sign extended,
-  /// and doubles stored into Pointer<[Float]> lose precision.
-  external void store(@DartRepresentationOf("T") Object value);
-
-  /// Load a Dart value from this location.
-  ///
-  /// The value is automatically unmarshalled from its native representation.
-  /// Loading a [Struct] reference returns a reference backed by native memory
-  /// (the same pointer as it's loaded from).
-  external R load<@DartRepresentationOf("T") R>();
-
   /// Access to the raw pointer value.
   /// On 32-bit systems, the upper 32-bits of the result are 0.
   external int get address;
@@ -82,11 +63,6 @@
   /// Pointer arithmetic (takes element size into account).
   external Pointer<T> elementAt(int index);
 
-  /// Pointer arithmetic (byte offset).
-  // TODO(dacoharkes): remove this?
-  // https://github.com/dart-lang/sdk/issues/35883
-  external Pointer<T> offsetBy(int offsetInBytes);
-
   /// Cast Pointer<T> to a Pointer<V>.
   external Pointer<U> cast<U extends NativeType>();
 
@@ -97,40 +73,6 @@
   /// invocations -- where the type of the receiver is [dynamic].
   external R asFunction<@DartRepresentationOf("T") R extends Function>();
 
-  /// Free memory on the C heap pointed to by this pointer with free().
-  ///
-  /// Note that this zeros out the address.
-  external void free();
-
-  /// Creates an *external* typed data array backed by this pointer.
-  ///
-  /// The typed data array returned is only valid for as long as the backing
-  /// [Pointer]. Accessing any element of the type data array after this
-  /// [Pointer] has been [Pointer.free()]d will cause undefined behavior.
-  ///
-  /// Since [Pointer]s do not know their length, the size of the typed data is
-  /// controlled by `count`, in units of the size of the native type for this
-  /// [Pointer] (similarly to [Pointer.allocate]).
-  ///
-  /// The kind of TypedData produced depends on the native type:
-  ///
-  ///   Pointer<Int8> -> Int8List
-  ///   Pointer<Uint8> -> Uint8List
-  ///   etc. up to Int64/Uint64
-  ///   Pointer<IntPtr> -> Int32List/Int64List depending on platform word size
-  ///   Pointer<Float> -> Float32List
-  ///   Pointer<Double> -> Float64List
-  ///
-  /// Creation of a [Uint8ClampedList] is not supported. Creation of a typed
-  /// data from a [Pointer] to any other native type is not supported.
-  ///
-  /// The pointer must be aligned to a multiple of the native type's size.
-  //
-  // TODO(37773): Use extension methods to articulate more precise return types.
-  // We should still keep this member though as a generic way to access a
-  // Pointer of unknown type.
-  external TypedData asExternalTypedData({int count: 1});
-
   /// Equality for Pointers only depends on their address.
   bool operator ==(other) {
     if (other == null) return false;
@@ -142,3 +84,528 @@
     return address.hashCode;
   }
 }
+
+//
+// The following code is generated, do not edit by hand.
+//
+// Code generated by `runtime/tools/ffi/sdk_lib_ffi_generator.dart`.
+//
+
+/// Extension on [Pointer] specialized for the type argument [Int8].
+extension Int8Pointer on Pointer<Int8> {
+  /// The 8-bit two's complement integer at [address].
+  ///
+  /// A Dart integer is truncated to 8 bits (as if by `.toSigned(8)`) before
+  /// being stored, and the 8-bit value is sign-extended when it is loaded.
+  external int get value;
+
+  /// The 8-bit two's complement integer at [address].
+  ///
+  /// A Dart integer is truncated to 8 bits (as if by `.toSigned(8)`) before
+  /// being stored, and the 8-bit value is sign-extended when it is loaded.
+  external void set value(int value);
+
+  /// The 8-bit two's complement integer at `address + index`.
+  ///
+  /// A Dart integer is truncated to 8 bits (as if by `.toSigned(8)`) before
+  /// being stored, and the 8-bit value is sign-extended when it is loaded.
+  external int operator [](int index);
+
+  /// The 8-bit two's complement integer at `address + index`.
+  ///
+  /// A Dart integer is truncated to 8 bits (as if by `.toSigned(8)`) before
+  /// being stored, and the 8-bit value is sign-extended when it is loaded.
+  external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Int8List asTypedList(int length);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Int16].
+extension Int16Pointer on Pointer<Int16> {
+  /// The 16-bit two's complement integer at [address].
+  ///
+  /// A Dart integer is truncated to 16 bits (as if by `.toSigned(16)`) before
+  /// being stored, and the 16-bit value is sign-extended when it is loaded.
+  ///
+  /// The [address] must be 2-byte aligned.
+  external int get value;
+
+  /// The 16-bit two's complement integer at [address].
+  ///
+  /// A Dart integer is truncated to 16 bits (as if by `.toSigned(16)`) before
+  /// being stored, and the 16-bit value is sign-extended when it is loaded.
+  ///
+  /// The [address] must be 2-byte aligned.
+  external void set value(int value);
+
+  /// The 16-bit two's complement integer at `address + 2 * index`.
+  ///
+  /// A Dart integer is truncated to 16 bits (as if by `.toSigned(16)`) before
+  /// being stored, and the 16-bit value is sign-extended when it is loaded.
+  ///
+  /// The [address] must be 2-byte aligned.
+  external int operator [](int index);
+
+  /// The 16-bit two's complement integer at `address + 2 * index`.
+  ///
+  /// A Dart integer is truncated to 16 bits (as if by `.toSigned(16)`) before
+  /// being stored, and the 16-bit value is sign-extended when it is loaded.
+  ///
+  /// The [address] must be 2-byte aligned.
+  external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + 2 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  ///
+  /// The [address] must be 2-byte aligned.
+  external Int16List asTypedList(int length);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Int32].
+extension Int32Pointer on Pointer<Int32> {
+  /// The 32-bit two's complement integer at [address].
+  ///
+  /// A Dart integer is truncated to 32 bits (as if by `.toSigned(32)`) before
+  /// being stored, and the 32-bit value is sign-extended when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external int get value;
+
+  /// The 32-bit two's complement integer at [address].
+  ///
+  /// A Dart integer is truncated to 32 bits (as if by `.toSigned(32)`) before
+  /// being stored, and the 32-bit value is sign-extended when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external void set value(int value);
+
+  /// The 32-bit two's complement integer at `address + 4 * index`.
+  ///
+  /// A Dart integer is truncated to 32 bits (as if by `.toSigned(32)`) before
+  /// being stored, and the 32-bit value is sign-extended when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external int operator [](int index);
+
+  /// The 32-bit two's complement integer at `address + 4 * index`.
+  ///
+  /// A Dart integer is truncated to 32 bits (as if by `.toSigned(32)`) before
+  /// being stored, and the 32-bit value is sign-extended when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + 4 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external Int32List asTypedList(int length);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Int64].
+extension Int64Pointer on Pointer<Int64> {
+  /// The 64-bit two's complement integer at [address].
+  ///
+  /// The [address] must be 8-byte aligned.
+  external int get value;
+
+  /// The 64-bit two's complement integer at [address].
+  ///
+  /// The [address] must be 8-byte aligned.
+  external void set value(int value);
+
+  /// The 64-bit two's complement integer at `address + 8 * index`.
+  ///
+  /// The [address] must be 8-byte aligned.
+  external int operator [](int index);
+
+  /// The 64-bit two's complement integer at `address + 8 * index`.
+  ///
+  /// The [address] must be 8-byte aligned.
+  external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + 8 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  ///
+  /// The [address] must be 8-byte aligned.
+  external Int64List asTypedList(int length);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Uint8].
+extension Uint8Pointer on Pointer<Uint8> {
+  /// The 8-bit unsigned integer at [address].
+  ///
+  /// A Dart integer is truncated to 8 bits (as if by `.toUnsigned(8)`) before
+  /// being stored, and the 8-bit value is zero-extended when it is loaded.
+  external int get value;
+
+  /// The 8-bit unsigned integer at [address].
+  ///
+  /// A Dart integer is truncated to 8 bits (as if by `.toUnsigned(8)`) before
+  /// being stored, and the 8-bit value is zero-extended when it is loaded.
+  external void set value(int value);
+
+  /// The 8-bit unsigned integer at `address + index`.
+  ///
+  /// A Dart integer is truncated to 8 bits (as if by `.toUnsigned(8)`) before
+  /// being stored, and the 8-bit value is zero-extended when it is loaded.
+  external int operator [](int index);
+
+  /// The 8-bit unsigned integer at `address + index`.
+  ///
+  /// A Dart integer is truncated to 8 bits (as if by `.toUnsigned(8)`) before
+  /// being stored, and the 8-bit value is zero-extended when it is loaded.
+  external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Uint8List asTypedList(int length);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Uint16].
+extension Uint16Pointer on Pointer<Uint16> {
+  /// The 16-bit unsigned integer at [address].
+  ///
+  /// A Dart integer is truncated to 16 bits (as if by `.toUnsigned(16)`) before
+  /// being stored, and the 16-bit value is zero-extended when it is loaded.
+  ///
+  /// The [address] must be 2-byte aligned.
+  external int get value;
+
+  /// The 16-bit unsigned integer at [address].
+  ///
+  /// A Dart integer is truncated to 16 bits (as if by `.toUnsigned(16)`) before
+  /// being stored, and the 16-bit value is zero-extended when it is loaded.
+  ///
+  /// The [address] must be 2-byte aligned.
+  external void set value(int value);
+
+  /// The 16-bit unsigned integer at `address + 2 * index`.
+  ///
+  /// A Dart integer is truncated to 16 bits (as if by `.toUnsigned(16)`) before
+  /// being stored, and the 16-bit value is zero-extended when it is loaded.
+  ///
+  /// The [address] must be 2-byte aligned.
+  external int operator [](int index);
+
+  /// The 16-bit unsigned integer at `address + 2 * index`.
+  ///
+  /// A Dart integer is truncated to 16 bits (as if by `.toUnsigned(16)`) before
+  /// being stored, and the 16-bit value is zero-extended when it is loaded.
+  ///
+  /// The [address] must be 2-byte aligned.
+  external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + 2 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  ///
+  /// The [address] must be 2-byte aligned.
+  external Uint16List asTypedList(int length);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Uint32].
+extension Uint32Pointer on Pointer<Uint32> {
+  /// The 32-bit unsigned integer at [address].
+  ///
+  /// A Dart integer is truncated to 32 bits (as if by `.toUnsigned(32)`) before
+  /// being stored, and the 32-bit value is zero-extended when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external int get value;
+
+  /// The 32-bit unsigned integer at [address].
+  ///
+  /// A Dart integer is truncated to 32 bits (as if by `.toUnsigned(32)`) before
+  /// being stored, and the 32-bit value is zero-extended when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external void set value(int value);
+
+  /// The 32-bit unsigned integer at `address + 4 * index`.
+  ///
+  /// A Dart integer is truncated to 32 bits (as if by `.toUnsigned(32)`) before
+  /// being stored, and the 32-bit value is zero-extended when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external int operator [](int index);
+
+  /// The 32-bit unsigned integer at `address + 4 * index`.
+  ///
+  /// A Dart integer is truncated to 32 bits (as if by `.toUnsigned(32)`) before
+  /// being stored, and the 32-bit value is zero-extended when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + 4 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external Uint32List asTypedList(int length);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Uint64].
+extension Uint64Pointer on Pointer<Uint64> {
+  /// The 64-bit unsigned integer at [address].
+  ///
+  /// The [address] must be 8-byte aligned.
+  external int get value;
+
+  /// The 64-bit unsigned integer at [address].
+  ///
+  /// The [address] must be 8-byte aligned.
+  external void set value(int value);
+
+  /// The 64-bit unsigned integer at `address + 8 * index`.
+  ///
+  /// The [address] must be 8-byte aligned.
+  external int operator [](int index);
+
+  /// The 64-bit unsigned integer at `address + 8 * index`.
+  ///
+  /// The [address] must be 8-byte aligned.
+  external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + 8 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  ///
+  /// The [address] must be 8-byte aligned.
+  external Uint64List asTypedList(int length);
+}
+
+/// Extension on [Pointer] specialized for the type argument [IntPtr].
+extension IntPtrPointer on Pointer<IntPtr> {
+  /// The 32 or 64-bit two's complement integer at [address].
+  ///
+  /// On 32-bit platforms this is a 32-bit integer, and on 64-bit platforms
+  /// this is a 64-bit integer.
+  ///
+  /// On 32-bit platforms a Dart integer is truncated to 32 bits (as if by
+  /// `.toSigned(32)`) before being stored, and the 32-bit value is
+  /// sign-extended when it is loaded.
+  ///
+  /// On 32-bit platforms the [address] must be 4-byte aligned, and on 64-bit
+  /// platforms the [address] must be 8-byte aligned.
+  external int get value;
+
+  /// The 32 or 64-bit two's complement integer at [address].
+  ///
+  /// On 32-bit platforms this is a 32-bit integer, and on 64-bit platforms
+  /// this is a 64-bit integer.
+  ///
+  /// On 32-bit platforms a Dart integer is truncated to 32 bits (as if by
+  /// `.toSigned(32)`) before being stored, and the 32-bit value is
+  /// sign-extended when it is loaded.
+  ///
+  /// On 32-bit platforms the [address] must be 4-byte aligned, and on 64-bit
+  /// platforms the [address] must be 8-byte aligned.
+  external void set value(int value);
+
+  /// The 32 or 64-bit two's complement integer at `address + (4 or 8) * index`.
+  ///
+  /// On 32-bit platforms this is a 32-bit integer, and on 64-bit platforms
+  /// this is a 64-bit integer.
+  ///
+  /// On 32-bit platforms a Dart integer is truncated to 32 bits (as if by
+  /// `.toSigned(32)`) before being stored, and the 32-bit value is
+  /// sign-extended when it is loaded.
+  ///
+  /// On 32-bit platforms the [address] must be 4-byte aligned, and on 64-bit
+  /// platforms the [address] must be 8-byte aligned.
+  external int operator [](int index);
+
+  /// The 32 or 64-bit two's complement integer at `address + (4 or 8) * index`.
+  ///
+  /// On 32-bit platforms this is a 32-bit integer, and on 64-bit platforms
+  /// this is a 64-bit integer.
+  ///
+  /// On 32-bit platforms a Dart integer is truncated to 32 bits (as if by
+  /// `.toSigned(32)`) before being stored, and the 32-bit value is
+  /// sign-extended when it is loaded.
+  ///
+  /// On 32-bit platforms the [address] must be 4-byte aligned, and on 64-bit
+  /// platforms the [address] must be 8-byte aligned.
+  external void operator []=(int index, int value);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Float].
+extension FloatPointer on Pointer<Float> {
+  /// The float at [address].
+  ///
+  /// A Dart double loses precision before being stored, and the float value is
+  /// converted to a double when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external double get value;
+
+  /// The float at [address].
+  ///
+  /// A Dart double loses precision before being stored, and the float value is
+  /// converted to a double when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external void set value(double value);
+
+  /// The float at `address + 4 * index`.
+  ///
+  /// A Dart double loses precision before being stored, and the float value is
+  /// converted to a double when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external double operator [](int index);
+
+  /// The float at `address + 4 * index`.
+  ///
+  /// A Dart double loses precision before being stored, and the float value is
+  /// converted to a double when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external void operator []=(int index, double value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + 4 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external Float32List asTypedList(int length);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Double].
+extension DoublePointer on Pointer<Double> {
+  /// The double at [address].
+  ///
+  /// The [address] must be 8-byte aligned.
+  external double get value;
+
+  /// The double at [address].
+  ///
+  /// The [address] must be 8-byte aligned.
+  external void set value(double value);
+
+  /// The double at `address + 8 * index`.
+  ///
+  /// The [address] must be 8-byte aligned.
+  external double operator [](int index);
+
+  /// The double at `address + 8 * index`.
+  ///
+  /// The [address] must be 8-byte aligned.
+  external void operator []=(int index, double value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + 8 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  ///
+  /// The [address] must be 8-byte aligned.
+  external Float64List asTypedList(int length);
+}
+
+//
+// End of generated code.
+//
+
+/// Extension on [Pointer] specialized for the type argument [Pointer].
+extension PointerPointer<T extends NativeType> on Pointer<Pointer<T>> {
+  /// The pointer at [address].
+  ///
+  /// A [Pointer] is unboxed before being stored (as if by `.address`), and the
+  /// pointer is boxed (as if by `Pointer.fromAddress`) when loaded.
+  ///
+  /// On 32-bit platforms the [address] must be 4-byte aligned, and on 64-bit
+  /// platforms the [address] must be 8-byte aligned.
+  external Pointer<T> get value;
+
+  /// Store a Dart value into this location.
+  ///
+  /// A [Pointer] is unboxed before being stored (as if by `.address`), and the
+  /// pointer is boxed (as if by `Pointer.fromAddress`) when loaded.
+  ///
+  /// On 32-bit platforms the [address] must be 4-byte aligned, and on 64-bit
+  /// platforms the [address] must be 8-byte aligned.
+  external void set value(Pointer<T> value);
+
+  /// Load a Dart value from this location offset by [index].
+  ///
+  /// A [Pointer] is unboxed before being stored (as if by `.address`), and the
+  /// pointer is boxed (as if by `Pointer.fromAddress`) when loaded.
+  ///
+  /// On 32-bit platforms the [address] must be 4-byte aligned, and on 64-bit
+  /// platforms the [address] must be 8-byte aligned.
+  external Pointer<T> operator [](int index);
+
+  /// Store a Dart value into this location offset by [index].
+  ///
+  /// A [Pointer] is unboxed before being stored (as if by `.address`), and the
+  /// pointer is boxed (as if by `Pointer.fromAddress`) when loaded.
+  ///
+  /// On 32-bit platforms the [address] must be 4-byte aligned, and on 64-bit
+  /// platforms the [address] must be 8-byte aligned.
+  external void operator []=(int index, Pointer<T> value);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Struct].
+extension StructPointer<T extends Struct> on Pointer<T> {
+  /// Creates a reference to access the fields of this struct backed by native
+  /// memory at [address].
+  ///
+  /// The [address] must be aligned according to the struct alignment rules of
+  /// the platform.
+  external T get ref;
+
+  /// Creates a reference to access the fields of this struct backed by native
+  /// memory at `address + sizeOf<T>() * index`.
+  ///
+  /// The [address] must be aligned according to the struct alignment rules of
+  /// the platform.
+  external T operator [](int index);
+}
diff --git a/sdk/lib/ffi/struct.dart b/sdk/lib/ffi/struct.dart
index 23124eb..c6605d8 100644
--- a/sdk/lib/ffi/struct.dart
+++ b/sdk/lib/ffi/struct.dart
@@ -15,12 +15,22 @@
 /// "@Int32()" for "int").
 ///
 /// Instances of a subclass of [Struct] have reference semantics and are backed
-/// by native memory. The may allocated via [Pointer.allocate] or loaded from a
+/// by native memory. The may allocated via allocation or loaded from a
 /// [Pointer], but not by a generative constructor.
-abstract class Struct<S extends NativeType> extends NativeType {
-  /// Returns the address backing the reference.
-  final Pointer<S> addressOf;
+abstract class Struct extends NativeType {
+  final Pointer<Struct> _addressOf;
 
-  Struct() : addressOf = null;
-  Struct.fromPointer(this.addressOf);
+  /// Construct a reference to the [nullptr].
+  ///
+  /// Use [StructPointer]'s `.ref` to gain references to native memory backed
+  /// structs.
+  Struct() : _addressOf = nullptr;
+
+  Struct._fromPointer(this._addressOf);
+}
+
+/// Extension on [Struct] specialized for it's subtypes.
+extension StructAddressOf<T extends Struct> on T {
+  /// Returns the address backing the reference.
+  Pointer<T> get addressOf => _addressOf as Pointer<T>;
 }
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index a8ce5d6..69474c6 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -66,8 +66,9 @@
         getNativeInterceptor,
         setDispatchProperty;
 
-export 'dart:math' show Rectangle, Point;
 export 'dart:_internal' show HttpStatus;
+export 'dart:html_common' show promiseToFuture;
+export 'dart:math' show Rectangle, Point;
 
 /**
  * Top-level container for a web page, which is usually a browser tab or window.
@@ -90,33 +91,13 @@
 HtmlDocument get document =>
     JS('returns:HtmlDocument;depends:none;effects:none;gvn:true', 'document');
 
-// Supoort to convert JS Promise to a Dart Future.
-Future<T> promiseToFuture<T>(jsPromise) {
-  var completer = new Completer<T>();
-
-  var thenSuccessCode = (promiseValue) => completer.complete(promiseValue);
-  var thenErrorCode = (promiseError) => completer.completeError(promiseError);
-
-  JS("", "#.then(#, #)", jsPromise, convertDartClosureToJS(thenSuccessCode, 1),
-      convertDartClosureToJS(thenErrorCode, 1));
-
-  return completer.future;
-}
-
-// Supoort to convert JS Promise to a Dart Future<Map<String, dynamic>>.  Each property of the JS
-// object is added to the Map as a key of type String with a value of type dynamic.
-Future<Map<String, dynamic>> promiseToFutureAsMap(jsPromise) {
-  var completer = new Completer<Map<String, dynamic>>();
-
-  var thenSuccessCode = (promiseValue) =>
-      completer.complete(convertNativeToDart_Dictionary(promiseValue));
-  var thenErrorCode = (promiseError) => completer.completeError(promiseError);
-
-  JS("", "#.then(#, #)", jsPromise, convertDartClosureToJS(thenSuccessCode, 1),
-      convertDartClosureToJS(thenErrorCode, 1));
-
-  return completer.future;
-}
+/// Convert a JS Promise to a Future<Map<String, dynamic>>.
+///
+/// On a successful result the native JS result will be converted to a Dart Map.
+/// See [convertNativeToDart_Dictionary]. On a rejected promise the error is
+/// forwarded without change.
+Future<Map<String, dynamic>> promiseToFutureAsMap(jsPromise) =>
+    promiseToFuture(jsPromise).then(convertNativeToDart_Dictionary);
 
 // Workaround for tags like <cite> that lack their own Element subclass --
 // Dart issue 1990.
@@ -12633,7 +12614,7 @@
    * [timing] paramter can be a double, representing the number of milliseconds
    * for the transition, or a Map with fields corresponding to those
    * of the [Timing] object.
-  **/
+   */
   @SupportedBrowser(SupportedBrowser.CHROME, '36')
   Animation animate(Iterable<Map<String, dynamic>> frames, [timing]) {
     if (frames is! Iterable || !(frames.every((x) => x is Map))) {
diff --git a/sdk/lib/html/html_common/conversions.dart b/sdk/lib/html/html_common/conversions.dart
index 5fa8385..a7775ed 100644
--- a/sdk/lib/html/html_common/conversions.dart
+++ b/sdk/lib/html/html_common/conversions.dart
@@ -236,7 +236,7 @@
     }
 
     if (isJavaScriptPromise(e)) {
-      return convertNativePromiseToDartFuture(e);
+      return promiseToFuture(e);
     }
 
     if (isJavaScriptSimpleObject(e)) {
diff --git a/sdk/lib/html/html_common/conversions_dart2js.dart b/sdk/lib/html/html_common/conversions_dart2js.dart
index d077775..625bb31 100644
--- a/sdk/lib/html/html_common/conversions_dart2js.dart
+++ b/sdk/lib/html/html_common/conversions_dart2js.dart
@@ -98,12 +98,11 @@
 bool isJavaScriptPromise(value) =>
     JS('bool', r'typeof Promise != "undefined" && # instanceof Promise', value);
 
-Future convertNativePromiseToDartFuture(promise) {
-  var completer = new Completer();
-  var then = convertDartClosureToJS((result) => completer.complete(result), 1);
-  var error =
-      convertDartClosureToJS((result) => completer.completeError(result), 1);
-  var newPromise = JS('', '#.then(#)["catch"](#)', promise, then, error);
+Future<T> promiseToFuture<T>(promise) {
+  var completer = new Completer<T>();
+  var then = convertDartClosureToJS((r) => completer.complete(r), 1);
+  var error = convertDartClosureToJS((e) => completer.completeError(e), 1);
+  JS('', '#.then(#, #)', promise, then, error);
   return completer.future;
 }
 
diff --git a/sdk/lib/io/file_system_entity.dart b/sdk/lib/io/file_system_entity.dart
index 16e99e6..dfff281 100644
--- a/sdk/lib/io/file_system_entity.dart
+++ b/sdk/lib/io/file_system_entity.dart
@@ -486,7 +486,9 @@
    *
    *   * The [Stream] is canceled, e.g. by calling `cancel` on the
    *      [StreamSubscription].
-   *   * The [FileSystemEntity] being watches, is deleted.
+   *   * The [FileSystemEntity] being watched, is deleted.
+   *   * System Watcher exits unexpectedly. e.g. On `Windows` this happens when
+   *     buffer that receive events from `ReadDirectoryChangesW` overflows.
    *
    * Use `events` to specify what events to listen for. The constants in
    * [FileSystemEvent] can be or'ed together to mix events. Default is
diff --git a/sdk/lib/isolate/isolate.dart b/sdk/lib/isolate/isolate.dart
index a697db4..8773cda 100644
--- a/sdk/lib/isolate/isolate.dart
+++ b/sdk/lib/isolate/isolate.dart
@@ -624,8 +624,7 @@
    * In the special circumstances when two isolates share the same code and are
    * running in the same process (e.g. isolates created via [Isolate.spawn]), it
    * is also possible to send object instances (which would be copied in the
-   * process). This is currently only supported by the dartvm.  For now, the
-   * dart2js compiler only supports the restricted messages described above.
+   * process). This is currently only supported by the dart vm.
    *
    * The send happens immediately and doesn't block.  The corresponding receive
    * port can receive the message as soon as its isolate's event loop is ready
diff --git a/sdk/lib/mirrors/mirrors.dart b/sdk/lib/mirrors/mirrors.dart
index 64f88a2..5e586a0 100644
--- a/sdk/lib/mirrors/mirrors.dart
+++ b/sdk/lib/mirrors/mirrors.dart
@@ -1071,6 +1071,11 @@
   bool get isFactoryConstructor;
 
   /**
+   * Is the reflectee an extension method?
+   */
+  bool get isExtensionMember;
+
+  /**
    * Whether this mirror is equal to [other].
    *
    * The equality holds if and only if
@@ -1112,6 +1117,11 @@
   bool get isConst;
 
   /**
+   * Is the reflectee an extension member?
+   */
+  bool get isExtensionMember;
+
+  /**
    * Whether this mirror is equal to [other].
    *
    * The equality holds if and only if
diff --git a/sdk_args.gni b/sdk_args.gni
new file mode 100644
index 0000000..0a66f18
--- /dev/null
+++ b/sdk_args.gni
@@ -0,0 +1,5 @@
+declare_args() {
+  # Whether to use the NNBD fork of the SDK core libraries.
+  # TODO(#38701): Remove this when the fork has been merged back in.
+  use_nnbd = false
+}
diff --git a/sdk_nnbd/BUILD.gn b/sdk_nnbd/BUILD.gn
index 3a2e18e..e352733 100644
--- a/sdk_nnbd/BUILD.gn
+++ b/sdk_nnbd/BUILD.gn
@@ -35,7 +35,7 @@
 # ......dartaotruntime or dartaotruntime.exe (executable)
 # ......dartdoc
 # ......dartfmt
-# ......dart2aot
+# ......dart2native
 # ......dart2js
 # ......dartanalyzer
 # ......dartdevc
@@ -51,11 +51,16 @@
 # ........gen_kernel.dart.snapshot
 # ........kernel_worker.dart.snapshot
 # ........pub.dart.snapshot
-#.........resources/
-#...........dartdoc/
-#..............packages
-#.............resources/
-#.............templates/
+# ......resources/
+# ........dartdoc/
+# ...........packages
+# ..........resources/
+# ..........templates/
+# ......model/
+# ........lexeme/
+# ..........idx2word.json
+# ..........model.tflite
+# ..........word2idx.json
 # ....include/
 # ......dart_api.h
 # ......dart_native_api.h
@@ -86,11 +91,6 @@
 # ......typed_data/
 # ......wasm/
 # ......api_readme.md
-# ....model/
-# ......lexeme/
-# ........idx2word.json
-# ........model.tflite
-# ........word2idx.json
 
 # Scripts that go under bin/
 _platform_sdk_scripts = [
@@ -311,7 +311,7 @@
         ":copy_libraries",
       ]
       source = "../pkg/analysis_server/language_model"
-      dest = "$root_out_dir/dart-sdk/model"
+      dest = "$root_out_dir/dart-sdk/bin/model"
       ignore_patterns = "{}"
     },
     {
@@ -435,19 +435,6 @@
   ]
 }
 
-copy("copy_dart2aot") {
-  ext = ""
-  if (is_win) {
-    ext = ".bat"
-  }
-  sources = [
-    "bin/dart2aot$ext",
-  ]
-  outputs = [
-    "$root_out_dir/dart-sdk/bin/{{source_file_part}}",
-  ]
-}
-
 copy("copy_dart2native") {
   deps = [
     ":copy_gen_kernel_snapshot",
diff --git a/sdk_nnbd/bin/dart2aot b/sdk_nnbd/bin/dart2aot
deleted file mode 100755
index 9390db6..0000000
--- a/sdk_nnbd/bin/dart2aot
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/usr/bin/env bash
-# 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.
-
-# Script for generating AOT snapshot in two steps:
-# - Compilation to kernel with additional AOT specific transformations.
-# - Compilation of kernel into snapshot using gen_snapshot.
-
-# Parse incoming arguments and extract the value of --packages option if any
-# was passed. Split options (--xyz) and non-options into two separate arrays.
-# All options will be passed to gen_snapshot, while --packages will be
-# passed to the CFE (Common Front-End).
-
-set -e
-
-OPTIONS=()
-GEN_KERNEL_OPTIONS=()
-PACKAGES=
-BUILD_ELF=0
-
-ARGV=()
-for arg in "$@"; do
-  case $arg in
-    --packages=*)
-    PACKAGES="$arg"
-    ;;
-    --enable-asserts)
-    GEN_KERNEL_OPTIONS+=("$arg")
-    OPTIONS+=("$arg")
-    ;;
-    --tfa | \
-    --no-tfa | \
-    -D* )
-    GEN_KERNEL_OPTIONS+=("$arg")
-    ;;
-    --build-elf)
-    BUILD_ELF=1
-    ;;
-    --*)
-    OPTIONS+=("$arg")
-    ;;
-    *)
-    ARGV+=("$arg")
-    ;;
-  esac
-done
-
-if [ "${#ARGV[@]}" -ne 2 ]; then
-    echo "Usage: $0 [options] <dart-source-file> <dart-aot-file>"
-    echo ""
-    echo "Dart AOT (ahead-of-time) compile Dart source code into native machine code."
-    exit 1
-fi
-
-SOURCE_FILE="${ARGV[0]}"
-SNAPSHOT_FILE="${ARGV[1]}"
-
-if [ $BUILD_ELF -eq 1 ]; then
-  GEN_SNAPSHOT_OPTION="--snapshot-kind=app-aot-assembly"
-  GEN_SNAPSHOT_FILENAME="--assembly=${SNAPSHOT_FILE}.S"
-else
-  GEN_SNAPSHOT_OPTION="--snapshot-kind=app-aot-blobs"
-  GEN_SNAPSHOT_FILENAME="--blobs_container_filename=${SNAPSHOT_FILE}"
-fi
-
-function follow_links() {
-  file="$1"
-  while [ -h "$file" ]; do
-    # On Mac OS, readlink -f doesn't work.
-    file="$(readlink "$file")"
-  done
-  echo "$file"
-}
-
-# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
-PROG_NAME="$(follow_links "$BASH_SOURCE")"
-
-# Handle the case where dart-sdk/bin has been symlinked to.
-BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
-
-SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
-
-DART="$BIN_DIR/dart"
-GEN_SNAPSHOT="$BIN_DIR/utils/gen_snapshot"
-
-SNAPSHOT_DIR="$BIN_DIR/snapshots"
-SNAPSHOT="$SNAPSHOT_DIR/gen_kernel.dart.snapshot"
-
-# Step 1: Generate Kernel binary from the input Dart source.
-"$DART"                                                                        \
-     "${SNAPSHOT}"                                                             \
-     --platform "${SDK_DIR}/lib/_internal/vm_platform_strong.dill"             \
-     --aot                                                                     \
-     -Ddart.vm.product=true                                                    \
-     "${GEN_KERNEL_OPTIONS[@]}"                                                \
-     $PACKAGES                                                                 \
-     -o "$SNAPSHOT_FILE.dill"                                                  \
-     "$SOURCE_FILE"
-
-# Step 2: Generate snapshot from the Kernel binary.
-"$GEN_SNAPSHOT"                                                                \
-     "$GEN_SNAPSHOT_OPTION"                                                    \
-     "$GEN_SNAPSHOT_FILENAME"                                                  \
-     "${OPTIONS[@]}"                                                           \
-     "$SNAPSHOT_FILE.dill"
-
-# Step 3: Assemble the assembly file into an ELF object.
-if [ $BUILD_ELF -eq 1 ]; then
-    gcc -shared -o "$SNAPSHOT_FILE" "${SNAPSHOT_FILE}.S"
-fi
diff --git a/sdk_nnbd/bin/dart2aot.bat b/sdk_nnbd/bin/dart2aot.bat
deleted file mode 100644
index 321e867..0000000
--- a/sdk_nnbd/bin/dart2aot.bat
+++ /dev/null
@@ -1,58 +0,0 @@
-@echo off
-REM Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
-REM for details. All rights reserved. Use of this source code is governed by a
-REM BSD-style license that can be found in the LICENSE file.
-
-setlocal
-rem Handle the case where dart-sdk/bin has been symlinked to.
-set DIR_NAME_WITH_SLASH=%~dp0
-set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
-call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
-rem Get rid of surrounding quotes.
-for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
-
-rem Get absolute full name for SDK_DIR.
-for %%i in ("%BIN_DIR%\..\") do set SDK_DIR=%%~fi
-
-rem Remove trailing backslash if there is one
-IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
-
-rem Get absolute full name for DART_ROOT.
-for %%i in ("%SDK_DIR%\..\") do set DART_ROOT=%%~fi
-
-rem Remove trailing backslash if there is one
-if %DART_ROOT:~-1%==\ set DART_ROOT=%DART_ROOT:~0,-1%
-
-set DART=%BIN_DIR%\dart.exe
-set GEN_KERNEL=%BIN_DIR%\snapshots\gen_kernel.dart.snapshot
-set VM_PLATFORM_STRONG=%SDK_DIR%\lib\_internal\vm_platform_strong.dill
-set GEN_SNAPSHOT=%BIN_DIR%\utils\gen_snapshot.exe
-
-set SOURCE_FILE=%1
-set SNAPSHOT_FILE=%2
-set GEN_SNAPSHOT_OPTION=--snapshot-kind=app-aot-blobs
-set GEN_SNAPSHOT_FILENAME=--blobs_container_filename=%SNAPSHOT_FILE%
-
-REM Step 1: Generate Kernel binary from the input Dart source.
-%DART% %GEN_KERNEL% --platform %VM_PLATFORM_STRONG% --aot -Ddart.vm.product=true -o %SNAPSHOT_FILE%.dill %SOURCE_FILE%
-
-REM Step 2: Generate snapshot from the Kernel binary.
-%GEN_SNAPSHOT% %GEN_SNAPSHOT_OPTION% %GEN_SNAPSHOT_FILENAME% %SNAPSHOT_FILE%.dill
-
-endlocal
-
-exit /b %errorlevel%
-
-:follow_links
-setlocal
-for %%i in (%1) do set result=%%~fi
-set current=
-for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
-                                             ^| %SystemRoot%\System32\find.exe ">     %~n1 [" 2^>nul`) do (
-  set current=%%i
-)
-if not "%current%"=="" call :follow_links "%current%", result
-endlocal & set %~2=%result%
-goto :eof
-
-:end
diff --git a/sdk_nnbd/bin/dartfix b/sdk_nnbd/bin/dartfix
new file mode 100755
index 0000000..bbeb80d
--- /dev/null
+++ b/sdk_nnbd/bin/dartfix
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+# 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.
+
+# Run dartfix.dart on the Dart VM. This script assumes the Dart SDK's
+# directory structure.
+
+function follow_links() {
+  file="$1"
+  while [ -h "$file" ]; do
+    # On Mac OS, readlink -f doesn't work.
+    file="$(readlink "$file")"
+  done
+  echo "$file"
+}
+
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
+
+SNAPSHOT="$BIN_DIR/snapshots/dartfix.dart.snapshot"
+
+# We are running the snapshot in the built SDK.
+DART="$BIN_DIR/dart"
+exec "$DART" "$SNAPSHOT" "$@"
diff --git a/sdk_nnbd/bin/dartfix.bat b/sdk_nnbd/bin/dartfix.bat
new file mode 100644
index 0000000..4241694
--- /dev/null
+++ b/sdk_nnbd/bin/dartfix.bat
@@ -0,0 +1,44 @@
+@echo off
+REM Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
+REM for details. All rights reserved. Use of this source code is governed by a
+REM BSD-style license that can be found in the LICENSE file.
+
+setlocal
+rem Handle the case where dart-sdk/bin has been symlinked to.
+set DIR_NAME_WITH_SLASH=%~dp0
+set DIR_NAME=%DIR_NAME_WITH_SLASH:~0,-1%%
+call :follow_links "%DIR_NAME%", RETURNED_BIN_DIR
+rem Get rid of surrounding quotes.
+for %%i in ("%RETURNED_BIN_DIR%") do set BIN_DIR=%%~fi
+
+set DART=%BIN_DIR%\dart
+set SNAPSHOT=%BIN_DIR%\snapshots\dartfix.dart.snapshot
+
+"%DART%" "%SNAPSHOT%" %*
+
+endlocal
+
+exit /b %errorlevel%
+
+rem Follow the symbolic links (junctions points) using `dir to determine the
+rem canonical path. Output with a link looks something like this
+rem
+rem 01/03/2013  10:11 PM    <JUNCTION>     abc def
+rem [c:\dart_bleeding\dart-repo.9\dart\out\ReleaseIA32\dart-sdk]
+rem
+rem So in the output of 'dir /a:l "targetdir"' we are looking for a filename
+rem surrounded by right angle bracket and left square bracket. Once we get
+rem the filename, which is name of the link, we recursively follow that.
+:follow_links
+setlocal
+for %%i in (%1) do set result=%%~fi
+set current=
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+                                             ^| find ">     %~n1 [" 2^>nul`) do (
+  set current=%%i
+)
+if not "%current%"=="" call :follow_links "%current%", result
+endlocal & set %~2=%result%
+goto :eof
+
+:end
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 7a8ac4b..3665c70 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
@@ -1023,9 +1023,7 @@
   static _BigIntImpl _tryParse(String source, {int radix}) {
     if (source == "") return null;
 
-    var re = RegExp(r'^\s*([+-]?)((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$',
-        caseSensitive: false);
-    var match = re.firstMatch(source);
+    var match = _parseRE.firstMatch(source);
     int signIndex = 1;
     int hexIndex = 3;
     int decimalIndex = 4;
@@ -1067,6 +1065,10 @@
         decimalMatch ?? nonDecimalMatch ?? hexMatch, radix, isNegative);
   }
 
+  static RegExp _parseRE = RegExp(
+      r'^\s*([+-]?)((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$',
+      caseSensitive: false);
+
   /// Finds the amount significant digits in the provided [digits] array.
   static int _normalize(int used, Uint16List digits) {
     while (used > 0 && digits[used - 1] == 0) used--;
diff --git a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
index 7451365..4aa1238 100644
--- a/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
+++ b/sdk_nnbd/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart
@@ -21,7 +21,7 @@
 ///
 ///   - All other types are represented as instances of class [DartType],
 ///     defined in this module.
-///     - Dynamic, Void, and Bottom are singleton instances of sentinal
+///     - Dynamic, Void, and Bottom are singleton instances of sentinel
 ///       classes.
 ///     - Function types are instances of subclasses of AbstractFunctionType.
 ///
@@ -202,6 +202,74 @@
   return ret;
 }
 
+/// Returns a nullable version of [type].
+///
+/// The resulting type will be normalized to avoid nesting the use of nullable
+/// (question) and legacy (star).
+@notNull
+DartType nullable(type) {
+  // Normalize and / or wrap the type.
+  // Given: T? -> T | Null
+  // Then: T?? -> T? | Null -> T | Null | Null -> T?
+  if (type is NullableType) return type;
+  // Then T*? -> (T? | T)? -> T?? | T? -> T?
+  if (type is LegacyType) return nullable(type.type);
+
+  return NullableType(type);
+}
+
+/// Returns a legacy version of [type].
+///
+/// The resulting type will be normalized to avoid nesting the use of nullable
+/// (question) and legacy (star).
+@notNull
+DartType legacy(type) {
+  // Normalize and / or wrap the type.
+  // Given: T* -> T? | T
+  // Then: T** -> T*? | T* ->  (T? | T)? | T? | T -> T? | T -> T*
+  // Then: T?* -> T?? | T? -> T?
+  if (type is LegacyType || type is NullableType) return type;
+
+  return LegacyType(type);
+}
+
+// TODO(nshahan) Revisit this representation to support caching of the subtype
+// check results.
+class NullableType extends DartType {
+  final Type type;
+
+  NullableType(this.type);
+
+  @override
+  String get name => '$type?';
+
+  @override
+  String toString() => name;
+}
+
+// TODO(nshahan) Revisit this representation to support caching of the subtype
+// check results.
+class LegacyType extends DartType {
+  final Type type;
+
+  LegacyType(this.type);
+
+  @override
+  String get name => '$type*';
+
+  @override
+  String toString() => name;
+}
+
+// TODO(nshahan) Add override optimizations for is, as and _check?
+class NeverType extends DartType {
+  @override
+  toString() => 'Never';
+}
+
+@JSExportName('Never')
+final never_ = NeverType();
+
 @JSExportName('dynamic')
 final _dynamic = DynamicType();
 
@@ -212,13 +280,12 @@
 @JSExportName('void')
 final void_ = VoidType();
 
+// TODO(nshahan): Cleanup and consolidate NeverType, BottomType, bottom, never_.
 class BottomType extends DartType {
   toString() => 'bottom';
 }
 
-// TODO(vsm): We reify bottom as Null.  We will revisit this with
-// non-nullable types.
-final bottom = unwrapType(Null);
+final bottom = never_;
 
 class JSObjectType extends DartType {
   toString() => 'NativeJavaScriptObject';
@@ -847,51 +914,115 @@
 bool isSubtypeOf(Object t1, Object t2) {
   // TODO(jmesserly): we've optimized `is`/`as`/implicit type checks, so they're
   // dispatched on the type. Can we optimize the subtype relation too?
-  Object map;
-  if (JS('!', '!#.hasOwnProperty(#)', t1, _subtypeCache)) {
-    JS('', '#[#] = # = new Map()', t1, _subtypeCache, map);
-    _cacheMaps.add(map);
-  } else {
-    map = JS('', '#[#]', t1, _subtypeCache);
-    bool result = JS('', '#.get(#)', map, t2);
-    if (JS('!', '# !== void 0', result)) return result;
-  }
+  // Object map;
+  // if (JS('!', '!#.hasOwnProperty(#)', t1, _subtypeCache)) {
+  //   JS('', '#[#] = # = new Map()', t1, _subtypeCache, map);
+  //   _cacheMaps.add(map);
+  // } else {
+  //   map = JS('', '#[#]', t1, _subtypeCache);
+  //   bool result = JS('', '#.get(#)', map, t2);
+  //   if (JS('!', '# !== void 0', result)) return result;
+  // }
+  // TODO(nshahan) Read and write cache when it's stored on nnbd-wrapper type.
+  // TODO(nshahan): Add support for strict/weak mode.
   var result = _isSubtype(t1, t2);
-  JS('', '#.set(#, #)', map, t2, result);
+  // JS('', '#.set(#, #)', map, t2, result);
   return result;
 }
 
 final _subtypeCache = JS('', 'Symbol("_subtypeCache")');
 
+// TODO(nshahan): Add support for strict/weak mode.
 @notNull
-bool _isBottom(type) => JS('!', '# == # || # == #', type, bottom, type, Null);
+bool _isBottom(type) => JS('!', '# == #', type, bottom);
 
+// TODO(nshahan): Add support for strict/weak mode.
 @notNull
 bool _isTop(type) {
   if (_isFutureOr(type)) {
     return _isTop(JS('', '#[0]', getGenericArgs(type)));
   }
-  return JS('!', '# == # || # == # || # == #', type, Object, type, dynamic,
-      type, void_);
+
+  if (_isNullable(type)) {
+    if (JS('!', '# == #', type.type, Object)) {
+      return true;
+    }
+    // TODO(nshahan): Revisit after deciding on normalization of NNBD top types.
+    // TODO(nshahan): Handle Object* in a way that ensures
+    // instanceOf(null, Object*) returns true.
+    return _isTop(type.type);
+  }
+
+  if (_isLegacy(type)) {
+    // TODO(nshahan): Revisit after deciding on normalization of NNBD top types.
+    return _isTop(type.type);
+  }
+
+  return JS('!', '# == # || # == #', type, dynamic, type, void_);
 }
 
+_isNullable(Type type) => JS<bool>('!', '$type instanceof $NullableType');
+_isLegacy(Type type) => JS<bool>('!', '$type instanceof $LegacyType');
+
 @notNull
 bool _isFutureOr(type) =>
     identical(getGenericClass(type), getGenericClass(FutureOr));
 
-bool _isSubtype(t1, t2) => JS('', '''(() => {
+bool _isSubtype(t1, t2) => JS('bool', '''(() => {
   if ($t1 === $t2) {
     return true;
   }
 
-  // Trivially true.
+  // Trivially true, "Right Top" or "Left Bottom".
   if (${_isTop(t2)} || ${_isBottom(t1)}) {
     return true;
   }
 
-  // Trivially false.
-  if (${_isTop(t1)} || ${_isBottom(t2)}) {
-    return false;
+  // "Left Top".
+  if ($t1 == $dynamic || $t1 == $void_) {
+    return $_isSubtype($nullable($Object), $t2);
+  }
+
+  // "Right Object".
+  if ($t2 == $Object) {
+    // TODO(nshahan) Need to handle type variables.
+    // https://github.com/dart-lang/sdk/issues/38816
+    if (${_isFutureOr(t1)}) {
+      let t1TypeArg = ${getGenericArgs(t1)}[0];
+      return $_isSubtype(t1TypeArg, $Object);
+    }
+
+    if (${_isLegacy(t1)}) {
+      return $_isSubtype(t1.type, t2);
+    }
+
+    if ($t1 == $dynamic || $t1 == $void_ || $t1 == $Null
+        || ${_isNullable(t1)}) {
+      return false;
+    }
+    return true;
+  }
+
+  // "Left Null".
+  if ($t1 == $Null) {
+    // TODO(nshahan) Need to handle type variables.
+    // https://github.com/dart-lang/sdk/issues/38816
+    if (${_isFutureOr(t2)}) {
+      let t2TypeArg = ${getGenericArgs(t2)}[0];
+      return $_isSubtype($Null, t2TypeArg);
+    }
+
+    return $t2 == $Null || ${_isLegacy(t2)} || ${_isNullable(t2)};
+  }
+
+  // "Left Legacy".
+  if (${_isLegacy(t1)}) {
+    return $_isSubtype(t1.type, t2);
+  }
+
+  // "Right Legacy".
+  if (${_isLegacy(t2)}) {
+    return $_isSubtype(t1, $nullable(t2.type));
   }
 
   // Handle FutureOr<T> union type.
@@ -900,6 +1031,8 @@
     if (${_isFutureOr(t2)}) {
       let t2TypeArg = ${getGenericArgs(t2)}[0];
       // FutureOr<A> <: FutureOr<B> iff A <: B
+      // TODO(nshahan): Proven to not actually be true and needs cleanup.
+      // https://github.com/dart-lang/sdk/issues/38818
       return $_isSubtype(t1TypeArg, t2TypeArg);
     }
 
@@ -910,14 +1043,30 @@
     return $_isSubtype(t1Future, $t2) && $_isSubtype(t1TypeArg, $t2);
   }
 
+  // "Left Nullable".
+  if (${_isNullable(t1)}) {
+    // TODO(nshahan) Need to handle type variables.
+    // https://github.com/dart-lang/sdk/issues/38816
+    return $_isSubtype(t1.type, t2) && $_isSubtype($Null, t2);
+  }
+
   if ($_isFutureOr($t2)) {
     // given t2 is Future<A> | A, then:
     // t1 <: (Future<A> | A) iff t1 <: Future<A> or t1 <: A
     let t2TypeArg = ${getGenericArgs(t2)}[0];
     let t2Future = ${getGenericClass(Future)}(t2TypeArg);
+    // TODO(nshahan) Need to handle type variables on the left.
+    // https://github.com/dart-lang/sdk/issues/38816
     return $_isSubtype($t1, t2Future) || $_isSubtype($t1, t2TypeArg);
   }
 
+  // "Right Nullable".
+  if (${_isNullable(t2)}) {
+    // TODO(nshahan) Need to handle type variables.
+    // https://github.com/dart-lang/sdk/issues/38816
+    return $_isSubtype(t1, t2.type) || $_isSubtype(t1, $Null);
+  }
+
   // "Traditional" name-based subtype check.  Avoid passing
   // function types to the class subtype checks, since we don't
   // currently distinguish between generic typedefs and classes.
diff --git a/sdk_nnbd/lib/_internal/js_runtime/interceptors_sources.gni b/sdk_nnbd/lib/_internal/js_runtime/interceptors_sources.gni
new file mode 100644
index 0000000..b3a8760
--- /dev/null
+++ b/sdk_nnbd/lib/_internal/js_runtime/interceptors_sources.gni
@@ -0,0 +1,5 @@
+# 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.
+
+interceptors_sdk_sources = [ "lib/interceptors.dart" ]
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 3fb8ccd..64c10cd 100644
--- a/sdk_nnbd/lib/_internal/js_runtime/lib/core_patch.dart
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/core_patch.dart
@@ -1073,9 +1073,7 @@
   static _BigIntImpl _tryParse(String source, {int radix}) {
     if (source == "") return null;
 
-    var re = new RegExp(r'^\s*([+-]?)((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$',
-        caseSensitive: false);
-    var match = re.firstMatch(source);
+    var match = _parseRE.firstMatch(source);
     int signIndex = 1;
     int hexIndex = 3;
     int decimalIndex = 4;
@@ -1117,6 +1115,10 @@
         decimalMatch ?? nonDecimalMatch ?? hexMatch, radix, isNegative);
   }
 
+  static RegExp _parseRE = RegExp(
+      r'^\s*([+-]?)((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$',
+      caseSensitive: false);
+
   /// Finds the amount significant digits in the provided [digits] array.
   static int _normalize(int used, Uint16List digits) {
     while (used > 0 && digits[used - 1] == 0) used--;
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/js_helper.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/js_helper.dart
index b8640d7..eda4d66 100644
--- a/sdk_nnbd/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/js_helper.dart
@@ -2282,7 +2282,8 @@
     if (JS('bool', 'typeof # == "string"', functionType)) {
       // A recipe to evaluate against the instance type.
       if (isStatic) {
-        throw 'TODO: Recipe for static tearoff.';
+        // TODO(sra): Recipe for static tearoff.
+        throw 'Cannot compute signature for static tearoff.';
       }
       var typeEvalMethod = isIntercepted
           ? RAW_DART_FUNCTION_REF(BoundClosure.evalRecipeIntercepted)
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/js_rti.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/js_rti.dart
index 2f06cbc..8f84174 100644
--- a/sdk_nnbd/lib/_internal/js_runtime/lib/js_rti.dart
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/js_rti.dart
@@ -708,13 +708,10 @@
     return false;
   }
 
-  // Generic function type parameters must match exactly, which would have
-  // exited earlier. The de Bruijn indexing ensures the representation as a
-  // small number can be used for type comparison.
   if (isGenericFunctionTypeParameter(s)) {
-    // TODO(sra): Use the bound of the type variable.
-    return false;
+    return _isSubtype(getIndex(sEnv, s), sEnv, t, tEnv);
   }
+
   if (isGenericFunctionTypeParameter(t)) return false;
 
   if (isNullType(s)) return true;
@@ -811,9 +808,8 @@
     if (sGenericParameters != tGenericParameters) return false;
     // TODO(sra): Compare bounds, which should be 'equal' trees due to the de
     // Bruijn numbering of type parameters.
-    // TODO(sra): Extend [sEnv] and [tEnv] with bindings for the [s] and [t]
-    // type parameters to enable checking the bound against non-type-parameter
-    // terms.
+    sEnv = sEnv == null ? sBounds : concat(sBounds, sEnv);
+    tEnv = tEnv == null ? tBounds : concat(tBounds, tEnv);
   } else if (hasField(t, genericBoundsTag)) {
     return false;
   }
@@ -1129,3 +1125,5 @@
         rti,
         JS_BUILTIN(
             'depends:none;effects:none;', JsBuiltin.dartObjectConstructor));
+
+concat(Object a1, Object a2) => JS('JSArray', '#.concat(#)', a1, a2);
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart
index bba55ef..0f35ac9 100644
--- a/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart
@@ -2145,11 +2145,6 @@
     return false;
   }
 
-  // Generic function type parameters must match exactly, which would have
-  // exited earlier.
-  if (isGenericFunctionTypeParameter(s)) return false;
-  if (isGenericFunctionTypeParameter(t)) return false;
-
   if (isNullType(s)) return true;
 
   if (isFutureOrType(t)) {
@@ -2171,6 +2166,18 @@
     }
   }
 
+  // If [s] and [t] are both generic function type parameters, they must be
+  // equal (as de Bruijn indices). This case is taken care of by the reflexivity
+  // check above, so it suffices to check that B <: [t] where B is the bound of
+  // [s].
+  if (isGenericFunctionTypeParameter(s)) {
+    int index = Rti._getGenericFunctionParameterIndex(s);
+    Rti bound = _castToRti(_Utils.arrayAt(sEnv, index));
+    return _isSubtype(universe, bound, sEnv, t, tEnv);
+  }
+
+  if (isGenericFunctionTypeParameter(t)) return false;
+
   // TODO(fishythefish): Disallow JavaScriptFunction as a subtype of function
   // types using features inaccessible from JavaScript.
 
@@ -2202,9 +2209,9 @@
   var sBounds = Rti._getGenericFunctionBounds(s);
   var tBounds = Rti._getGenericFunctionBounds(t);
   if (!typesEqual(sBounds, tBounds)) return false;
-  // TODO(fishythefish): Extend [sEnv] and [tEnv] with bindings for the [s]
-  // and [t] type parameters to enable checking the bound against
-  // non-type-parameter terms.
+
+  sEnv = sEnv == null ? sBounds : _Utils.arrayConcat(sBounds, sEnv);
+  tEnv = tEnv == null ? tBounds : _Utils.arrayConcat(tBounds, tEnv);
 
   return _isFunctionSubtype(universe, Rti._getGenericFunctionBase(s), sEnv,
       Rti._getGenericFunctionBase(t), tEnv);
diff --git a/sdk_nnbd/lib/_internal/vm/bin/file_patch.dart b/sdk_nnbd/lib/_internal/vm/bin/file_patch.dart
index 3ebdc82..03ebb71 100644
--- a/sdk_nnbd/lib/_internal/vm/bin/file_patch.dart
+++ b/sdk_nnbd/lib/_internal/vm/bin/file_patch.dart
@@ -296,6 +296,19 @@
         }
       } else if (event == RawSocketEvent.closed) {
       } else if (event == RawSocketEvent.readClosed) {
+        // If Directory watcher buffer overflows, it will send an readClosed event.
+        // Normal closing will cancel stream subscription so that path is
+        // no longer being watched, not present in _idMap.
+        if (_idMap.containsKey(pathId)) {
+          var path = _pathFromPathId(pathId).path;
+          _idMap.remove(pathId);
+          if (_idMap.isEmpty && _id != null) {
+            _closeWatcher(_id);
+            _id = null;
+          }
+          throw FileSystemException(
+              'Directory watcher closed unexpectedly', path);
+        }
       } else {
         assert(false);
       }
diff --git a/sdk_nnbd/lib/_internal/vm/lib/bigint_patch.dart b/sdk_nnbd/lib/_internal/vm/lib/bigint_patch.dart
index 1730be8..b5d3093 100644
--- a/sdk_nnbd/lib/_internal/vm/lib/bigint_patch.dart
+++ b/sdk_nnbd/lib/_internal/vm/lib/bigint_patch.dart
@@ -271,9 +271,7 @@
   static _BigIntImpl _tryParse(String source, {int radix}) {
     if (source == "") return null;
 
-    var re = new RegExp(r'^\s*([+-]?)((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$',
-        caseSensitive: false);
-    var match = re.firstMatch(source);
+    var match = _parseRE.firstMatch(source);
     int signIndex = 1;
     int hexIndex = 3;
     int decimalIndex = 4;
@@ -315,6 +313,10 @@
         decimalMatch ?? nonDecimalMatch ?? hexMatch, radix, isNegative);
   }
 
+  static RegExp _parseRE = RegExp(
+      r'^\s*([+-]?)((0x[a-f0-9]+)|(\d+)|([a-z0-9]+))\s*$',
+      caseSensitive: false);
+
   /// Finds the amount significant digits in the provided [digits] array.
   static int _normalize(int used, Uint32List digits) {
     while (used > 0 && digits[used - 1] == 0) used--;
diff --git a/sdk_nnbd/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart b/sdk_nnbd/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart
index 581582f..dc2be0d 100644
--- a/sdk_nnbd/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart
+++ b/sdk_nnbd/lib/_internal/vm/lib/ffi_dynamic_library_patch.dart
@@ -7,7 +7,7 @@
 // All imports must be in all FFI patch files to not depend on the order
 // the patches are applied.
 import "dart:_internal" show patch;
-import 'dart:typed_data' show TypedData;
+import 'dart:typed_data';
 
 DynamicLibrary _open(String name) native "Ffi_dl_open";
 DynamicLibrary _processLibrary() native "Ffi_dl_processLibrary";
diff --git a/sdk_nnbd/lib/_internal/vm/lib/ffi_native_type_patch.dart b/sdk_nnbd/lib/_internal/vm/lib/ffi_native_type_patch.dart
index 876184d..6824c19 100644
--- a/sdk_nnbd/lib/_internal/vm/lib/ffi_native_type_patch.dart
+++ b/sdk_nnbd/lib/_internal/vm/lib/ffi_native_type_patch.dart
@@ -7,7 +7,7 @@
 // All imports must be in all FFI patch files to not depend on the order
 // the patches are applied.
 import "dart:_internal" show patch;
-import 'dart:typed_data' show TypedData;
+import 'dart:typed_data';
 
 // NativeType is not private, because it is used in type arguments.
 // NativeType is abstract because it not used with const constructors in
diff --git a/sdk_nnbd/lib/_internal/vm/lib/ffi_patch.dart b/sdk_nnbd/lib/_internal/vm/lib/ffi_patch.dart
index 25c3f41..55ba588 100644
--- a/sdk_nnbd/lib/_internal/vm/lib/ffi_patch.dart
+++ b/sdk_nnbd/lib/_internal/vm/lib/ffi_patch.dart
@@ -7,13 +7,39 @@
 // All imports must be in all FFI patch files to not depend on the order
 // the patches are applied.
 import "dart:_internal" show patch;
-import 'dart:typed_data' show TypedData;
+import 'dart:typed_data';
+
+const Map<Type, int> _knownSizes = {
+  Int8: 1,
+  Uint8: 1,
+  Int16: 2,
+  Uint16: 2,
+  Int32: 4,
+  Uint32: 4,
+  Int64: 8,
+  Uint64: 8,
+  Float: 4,
+  Double: 8,
+};
+
+final int _intPtrSize = [8, 4, 4][_abi()];
 
 @patch
-int sizeOf<T extends NativeType>() native "Ffi_sizeOf";
+int sizeOf<T extends NativeType>() {
+  // This is not super fast, but it is faster than a runtime entry.
+  // Hot loops with elementAt().load() do not use this sizeOf, elementAt is
+  // optimized per NativeType statically to prevent use of sizeOf at runtime.
+  final int knownSize = _knownSizes[T];
+  if (knownSize != null) return knownSize;
+  if (T == IntPtr) return _intPtrSize;
+  if (T == Pointer) return _intPtrSize;
+  // For structs we fall back to a runtime entry.
+  return _sizeOf<T>();
+}
 
-Pointer<T> _allocate<T extends NativeType>(int count) native "Ffi_allocate";
+int _sizeOf<T extends NativeType>() native "Ffi_sizeOf";
 
+// Implemented in the method recognizer, bytecode interpreter uses runtime.
 Pointer<T> _fromAddress<T extends NativeType>(int ptr) native "Ffi_fromAddress";
 
 // The real implementation of this function (for interface calls) lives in
@@ -25,64 +51,396 @@
 dynamic _asExternalTypedData(Pointer ptr, int count)
     native "Ffi_asExternalTypedData";
 
+// Returns a Function object for a native callback.
+//
+// Calls to [Pointer.fromFunction] are re-written by the FE into calls to this
+// method + _pointerFromFunction. All three arguments must be constants.
+//
+// In AOT we evaluate calls to this function during precompilation and replace
+// them with Constant instruction referencing the callback trampoline, to ensure
+// that it will be precompiled.
+//
+// In all JIT modes we call a native runtime entry. We *cannot* use the IL
+// implementation, since that would pull the callback trampoline into JIT
+// snapshots. The callback trampolines can only be serialized into AOT snapshots
+// because they embed the addresses of runtime routines in JIT mode.
+Object _nativeCallbackFunction<NS extends Function>(Function target,
+    Object exceptionalReturn) native "Ffi_nativeCallbackFunction";
+
+Pointer<NS> _pointerFromFunction<NS extends NativeFunction>(Object function)
+    native "Ffi_pointerFromFunction";
+
 @patch
 @pragma("vm:entry-point")
 class Pointer<T extends NativeType> {
   @patch
-  factory Pointer.allocate({int count: 1}) => _allocate<T>(count);
-
-  @patch
   factory Pointer.fromAddress(int ptr) => _fromAddress(ptr);
 
+  // All static calls to this method are replaced by the FE into
+  // _nativeCallbackFunction + _pointerFromFunction.
+  //
+  // We still need to throw an error on a dynamic invocations, invocations
+  // through tearoffs or reflective calls.
   @patch
   static Pointer<NativeFunction<T>> fromFunction<T extends Function>(
       @DartRepresentationOf("T") Function f,
-      Object exceptionalReturn) native "Ffi_fromFunction";
+      [Object exceptionalReturn]) {
+    throw UnsupportedError(
+        "Pointer.fromFunction cannot be called dynamically.");
+  }
 
-  // TODO(sjindel): When NNBD is available, we should change `value` to be
-  // non-null.
-  @patch
-  void store(Object value) native "Ffi_store";
-
-  @patch
-  R load<R>() native "Ffi_load";
-
+  // Implemented in the method recognizer, bytecode interpreter uses runtime.
   @patch
   int get address native "Ffi_address";
 
-  // Note this could also be implmented without an extra native as offsetBy
-  // (elementSize()*index). This would be 2 native calls rather than one. What
-  // would be better?
+  // For statically known types, this is rewired.
+  // (Method sizeOf is slow, see notes above.)
   @patch
-  Pointer<T> elementAt(int index) native "Ffi_elementAt";
+  Pointer<T> elementAt(int index) =>
+      Pointer.fromAddress(address + sizeOf<T>() * index);
 
-  // Note this could also be implmented without an extra  native as
-  // fromAddress(address). This would be 2 native calls rather than one.
-  // What would be better?
   @patch
-  Pointer<T> offsetBy(int offsetInBytes) native "Ffi_offsetBy";
+  Pointer<T> _offsetBy(int offsetInBytes) =>
+      Pointer.fromAddress(address + offsetInBytes);
 
-  // Note this could also be implemented without an extra native as
-  // fromAddress(address). This would be 2 native calls rather than one.
-  // What would be better?
   @patch
-  Pointer<U> cast<U extends NativeType>() native "Ffi_cast";
+  Pointer<U> cast<U extends NativeType>() => Pointer.fromAddress(address);
 
   @patch
   R asFunction<R extends Function>() {
     throw UnsupportedError("Pointer.asFunction cannot be called dynamically.");
   }
-
-  @patch
-  void free() native "Ffi_free";
-
-  @patch
-  TypedData asExternalTypedData({int count: 1}) =>
-      _asExternalTypedData(this, count);
 }
 
-// Returns the ABI used for size and alignment calculations.
-// See pkg/vm/lib/transformations/ffi.dart.
+/// Returns an integer encoding the ABI used for size and alignment
+/// calculations. See pkg/vm/lib/transformations/ffi.dart.
 @pragma('vm:prefer-inline')
 int _abi()
     native "Recognized method: method is directly interpreted by the bytecode interpreter or IR graph is built in the flow graph builder.";
+
+// The following functions are implemented in the method recognizer, but the
+// bytecode interpreter uses native entries.
+//
+// TODO(38172): Since these are not inlined (force optimize), they force
+// allocating a Pointer with in elementAt/offsetBy. Allocating these pointers
+// and GCing new spaces takes a lot of the benchmark time. The next speedup is
+// getting rid of these allocations by inlining these functions.
+//
+// TODO(37773): Change _loadInt8 etc to take an index.
+int _loadInt8(Pointer<Int8> pointer, int index) native "Ffi_loadInt8";
+
+int _loadInt16(Pointer<Int16> pointer, int index) native "Ffi_loadInt16";
+
+int _loadInt32(Pointer<Int32> pointer, int index) native "Ffi_loadInt32";
+
+int _loadInt64(Pointer<Int64> pointer, int index) native "Ffi_loadInt64";
+
+int _loadUint8(Pointer<Uint8> pointer, int index) native "Ffi_loadUint8";
+
+int _loadUint16(Pointer<Uint16> pointer, int index) native "Ffi_loadUint16";
+
+int _loadUint32(Pointer<Uint32> pointer, int index) native "Ffi_loadUint32";
+
+int _loadUint64(Pointer<Uint64> pointer, int index) native "Ffi_loadUint64";
+
+int _loadIntPtr(Pointer<IntPtr> pointer, int index) native "Ffi_loadIntPtr";
+
+double _loadFloat(Pointer<Float> pointer, int index) native "Ffi_loadFloat";
+
+double _loadDouble(Pointer<Double> pointer, int index) native "Ffi_loadDouble";
+
+Pointer<S> _loadPointer<S extends NativeType>(
+    Pointer<Pointer<S>> pointer, int index) native "Ffi_loadPointer";
+
+S _loadStruct<S extends Struct>(Pointer<S> pointer, int index)
+    native "Ffi_loadStruct";
+
+void _storeInt8(Pointer<Int8> pointer, int index, int value)
+    native "Ffi_storeInt8";
+
+void _storeInt16(Pointer<Int16> pointer, int index, int value)
+    native "Ffi_storeInt16";
+
+void _storeInt32(Pointer<Int32> pointer, int index, int value)
+    native "Ffi_storeInt32";
+
+void _storeInt64(Pointer<Int64> pointer, int index, int value)
+    native "Ffi_storeInt64";
+
+void _storeUint8(Pointer<Uint8> pointer, int index, int value)
+    native "Ffi_storeUint8";
+
+void _storeUint16(Pointer<Uint16> pointer, int index, int value)
+    native "Ffi_storeUint16";
+
+void _storeUint32(Pointer<Uint32> pointer, int index, int value)
+    native "Ffi_storeUint32";
+
+void _storeUint64(Pointer<Uint64> pointer, int index, int value)
+    native "Ffi_storeUint64";
+
+void _storeIntPtr(Pointer<IntPtr> pointer, int index, int value)
+    native "Ffi_storeIntPtr";
+
+void _storeFloat(Pointer<Float> pointer, int index, double value)
+    native "Ffi_storeFloat";
+
+void _storeDouble(Pointer<Double> pointer, int index, double value)
+    native "Ffi_storeDouble";
+
+void _storePointer<S extends NativeType>(Pointer<Pointer<S>> pointer, int index,
+    Pointer<S> value) native "Ffi_storePointer";
+
+Pointer<Int8> _elementAtInt8(Pointer<Int8> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + 1 * index);
+
+Pointer<Int16> _elementAtInt16(Pointer<Int16> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + 2 * index);
+
+Pointer<Int32> _elementAtInt32(Pointer<Int32> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + 4 * index);
+
+Pointer<Int64> _elementAtInt64(Pointer<Int64> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + 8 * index);
+
+Pointer<Uint8> _elementAtUint8(Pointer<Uint8> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + 1 * index);
+
+Pointer<Uint16> _elementAtUint16(Pointer<Uint16> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + 2 * index);
+
+Pointer<Uint32> _elementAtUint32(Pointer<Uint32> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + 4 * index);
+
+Pointer<Uint64> _elementAtUint64(Pointer<Uint64> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + 8 * index);
+
+Pointer<IntPtr> _elementAtIntPtr(Pointer<IntPtr> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + _intPtrSize * index);
+
+Pointer<Float> _elementAtFloat(Pointer<Float> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + 4 * index);
+
+Pointer<Double> _elementAtDouble(Pointer<Double> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + 8 * index);
+
+Pointer<Pointer<S>> _elementAtPointer<S extends NativeType>(
+        Pointer<Pointer<S>> pointer, int index) =>
+    Pointer.fromAddress(pointer.address + _intPtrSize * index);
+
+//
+// The following code is generated, do not edit by hand.
+//
+// Code generated by `runtime/tools/ffi/sdk_lib_ffi_generator.dart`.
+//
+
+extension Int8Pointer on Pointer<Int8> {
+  @patch
+  int get value => _loadInt8(this, 0);
+
+  @patch
+  set value(int value) => _storeInt8(this, 0, value);
+
+  @patch
+  int operator [](int index) => _loadInt8(this, index);
+
+  @patch
+  operator []=(int index, int value) => _storeInt8(this, index, value);
+
+  @patch
+  Int8List asTypedList(int elements) => _asExternalTypedData(this, elements);
+}
+
+extension Int16Pointer on Pointer<Int16> {
+  @patch
+  int get value => _loadInt16(this, 0);
+
+  @patch
+  set value(int value) => _storeInt16(this, 0, value);
+
+  @patch
+  int operator [](int index) => _loadInt16(this, index);
+
+  @patch
+  operator []=(int index, int value) => _storeInt16(this, index, value);
+
+  @patch
+  Int16List asTypedList(int elements) => _asExternalTypedData(this, elements);
+}
+
+extension Int32Pointer on Pointer<Int32> {
+  @patch
+  int get value => _loadInt32(this, 0);
+
+  @patch
+  set value(int value) => _storeInt32(this, 0, value);
+
+  @patch
+  int operator [](int index) => _loadInt32(this, index);
+
+  @patch
+  operator []=(int index, int value) => _storeInt32(this, index, value);
+
+  @patch
+  Int32List asTypedList(int elements) => _asExternalTypedData(this, elements);
+}
+
+extension Int64Pointer on Pointer<Int64> {
+  @patch
+  int get value => _loadInt64(this, 0);
+
+  @patch
+  set value(int value) => _storeInt64(this, 0, value);
+
+  @patch
+  int operator [](int index) => _loadInt64(this, index);
+
+  @patch
+  operator []=(int index, int value) => _storeInt64(this, index, value);
+
+  @patch
+  Int64List asTypedList(int elements) => _asExternalTypedData(this, elements);
+}
+
+extension Uint8Pointer on Pointer<Uint8> {
+  @patch
+  int get value => _loadUint8(this, 0);
+
+  @patch
+  set value(int value) => _storeUint8(this, 0, value);
+
+  @patch
+  int operator [](int index) => _loadUint8(this, index);
+
+  @patch
+  operator []=(int index, int value) => _storeUint8(this, index, value);
+
+  @patch
+  Uint8List asTypedList(int elements) => _asExternalTypedData(this, elements);
+}
+
+extension Uint16Pointer on Pointer<Uint16> {
+  @patch
+  int get value => _loadUint16(this, 0);
+
+  @patch
+  set value(int value) => _storeUint16(this, 0, value);
+
+  @patch
+  int operator [](int index) => _loadUint16(this, index);
+
+  @patch
+  operator []=(int index, int value) => _storeUint16(this, index, value);
+
+  @patch
+  Uint16List asTypedList(int elements) => _asExternalTypedData(this, elements);
+}
+
+extension Uint32Pointer on Pointer<Uint32> {
+  @patch
+  int get value => _loadUint32(this, 0);
+
+  @patch
+  set value(int value) => _storeUint32(this, 0, value);
+
+  @patch
+  int operator [](int index) => _loadUint32(this, index);
+
+  @patch
+  operator []=(int index, int value) => _storeUint32(this, index, value);
+
+  @patch
+  Uint32List asTypedList(int elements) => _asExternalTypedData(this, elements);
+}
+
+extension Uint64Pointer on Pointer<Uint64> {
+  @patch
+  int get value => _loadUint64(this, 0);
+
+  @patch
+  set value(int value) => _storeUint64(this, 0, value);
+
+  @patch
+  int operator [](int index) => _loadUint64(this, index);
+
+  @patch
+  operator []=(int index, int value) => _storeUint64(this, index, value);
+
+  @patch
+  Uint64List asTypedList(int elements) => _asExternalTypedData(this, elements);
+}
+
+extension IntPtrPointer on Pointer<IntPtr> {
+  @patch
+  int get value => _loadIntPtr(this, 0);
+
+  @patch
+  set value(int value) => _storeIntPtr(this, 0, value);
+
+  @patch
+  int operator [](int index) => _loadIntPtr(this, index);
+
+  @patch
+  operator []=(int index, int value) => _storeIntPtr(this, index, value);
+}
+
+extension FloatPointer on Pointer<Float> {
+  @patch
+  double get value => _loadFloat(this, 0);
+
+  @patch
+  set value(double value) => _storeFloat(this, 0, value);
+
+  @patch
+  double operator [](int index) => _loadFloat(this, index);
+
+  @patch
+  operator []=(int index, double value) => _storeFloat(this, index, value);
+
+  @patch
+  Float32List asTypedList(int elements) => _asExternalTypedData(this, elements);
+}
+
+extension DoublePointer on Pointer<Double> {
+  @patch
+  double get value => _loadDouble(this, 0);
+
+  @patch
+  set value(double value) => _storeDouble(this, 0, value);
+
+  @patch
+  double operator [](int index) => _loadDouble(this, index);
+
+  @patch
+  operator []=(int index, double value) => _storeDouble(this, index, value);
+
+  @patch
+  Float64List asTypedList(int elements) => _asExternalTypedData(this, elements);
+}
+
+//
+// End of generated code.
+//
+
+extension PointerPointer<T extends NativeType> on Pointer<Pointer<T>> {
+  @patch
+  Pointer<T> get value => _loadPointer(this, 0);
+
+  @patch
+  set value(Pointer<T> value) => _storePointer(this, 0, value);
+
+  @patch
+  Pointer<T> operator [](int index) => _loadPointer(this, index);
+
+  @patch
+  operator []=(int index, Pointer<T> value) =>
+      _storePointer(this, index, value);
+}
+
+extension StructPointer<T extends Struct> on Pointer<T> {
+  @patch
+  T get ref => _loadStruct(this, 0);
+
+  @patch
+  T operator [](int index) => _loadStruct(this, index);
+}
diff --git a/sdk_nnbd/lib/_internal/vm/lib/mirrors_impl.dart b/sdk_nnbd/lib/_internal/vm/lib/mirrors_impl.dart
index f83fe33..b7512a0 100644
--- a/sdk_nnbd/lib/_internal/vm/lib/mirrors_impl.dart
+++ b/sdk_nnbd/lib/_internal/vm/lib/mirrors_impl.dart
@@ -159,6 +159,7 @@
   bool get isExternal => false;
   bool get isRedirectingConstructor => false;
   bool get isAbstract => false;
+  bool get isExtensionMember => false;
 
   bool get isSetter => !isGetter;
   bool get isPrivate => _n(simpleName).startsWith('_');
@@ -195,6 +196,7 @@
   bool get isConst => false;
   bool get isFinal => true;
   bool get isPrivate => false;
+  bool get isExtensionMember => false;
   bool get hasDefaultValue => false;
   InstanceMirror get defaultValue => null;
   SourceLocation get location => null;
@@ -1170,6 +1172,7 @@
   static const kFactoryCtor = 7;
   static const kExternal = 8;
   static const kSynthetic = 9;
+  static const kExtensionMember = 10;
 
   // These offsets much be kept in sync with those in mirrors.h.
   bool get isAbstract => 0 != (_kindFlags & (1 << kAbstract));
@@ -1184,6 +1187,7 @@
   bool get isFactoryConstructor => 0 != (_kindFlags & (1 << kFactoryCtor));
   bool get isExternal => 0 != (_kindFlags & (1 << kExternal));
   bool get isSynthetic => 0 != (_kindFlags & (1 << kSynthetic));
+  bool get isExtensionMember => 0 != (_kindFlags & (1 << kExtensionMember));
 
   static const _operators = const [
     "%", "&", "*", "+", "-", "/", "<", "<<", //
@@ -1283,9 +1287,10 @@
   final bool isStatic;
   final bool isFinal;
   final bool isConst;
+  final bool isExtensionMember;
 
   _VariableMirror._(reflectee, String simpleName, this.owner, this._type,
-      this.isStatic, this.isFinal, this.isConst)
+      this.isStatic, this.isFinal, this.isConst, this.isExtensionMember)
       : super._(reflectee, _s(simpleName));
 
   bool get isTopLevel => owner is LibraryMirror;
@@ -1341,7 +1346,8 @@
             null, // We override the type.
             false, // isStatic does not apply.
             isFinal,
-            false // Not const.
+            false, // Not const.
+            false // Not extension member.
             );
 
   Object _defaultValueReflectee;
diff --git a/sdk_nnbd/lib/developer/timeline.dart b/sdk_nnbd/lib/developer/timeline.dart
index 03e360c..56f4f16 100644
--- a/sdk_nnbd/lib/developer/timeline.dart
+++ b/sdk_nnbd/lib/developer/timeline.dart
@@ -192,12 +192,8 @@
 
   /// Create a task with an explicit [taskId]. This is useful if you are
   /// passing a task from one isolate to another.
-  ///
-  /// If [parent] is provided, the parent's task ID is provided as argument
-  /// 'parentId' when [start] is called. In DevTools, this argument will result
-  /// in this [TimelineTask] being linked to the [parent] [TimelineTask].
-  TimelineTask.withTaskId(int taskId, {TimelineTask parent})
-      : _parent = parent,
+  TimelineTask.withTaskId(int taskId)
+      : _parent = null,
         _taskId = taskId {
     ArgumentError.checkNotNull(taskId, 'taskId');
   }
diff --git a/sdk_nnbd/lib/ffi/annotations.dart b/sdk_nnbd/lib/ffi/annotations.dart
index c4e9b7f..7328cd1 100644
--- a/sdk_nnbd/lib/ffi/annotations.dart
+++ b/sdk_nnbd/lib/ffi/annotations.dart
@@ -23,7 +23,7 @@
   /// [Pointer]<T>                         -> [Pointer]<T>
   /// [NativeFunction]<T1 Function(T2, T3) -> S1 Function(S2, S3)
   ///    where DartRepresentationOf(Tn) -> Sn
-  /// T extends Struct<T>                  -> T
+  /// T extends Struct                  -> T
   const DartRepresentationOf(String nativeType);
 }
 
diff --git a/sdk_nnbd/lib/ffi/ffi.dart b/sdk_nnbd/lib/ffi/ffi.dart
index eb1bdcd..c00226f 100644
--- a/sdk_nnbd/lib/ffi/ffi.dart
+++ b/sdk_nnbd/lib/ffi/ffi.dart
@@ -16,7 +16,7 @@
  */
 library dart.ffi;
 
-import 'dart:typed_data' show TypedData;
+import 'dart:typed_data';
 
 part "native_type.dart";
 part "annotations.dart";
@@ -28,18 +28,13 @@
 /// Includes padding and alignment of structs.
 external int sizeOf<T extends NativeType>();
 
-/// Represents a pointer into the native C memory.
-final Pointer<Void> nullptr = Pointer.fromAddress(0);
+/// Represents a pointer into the native C memory corresponding to "NULL", e.g.
+/// a pointer with address 0.
+final Pointer<Null> nullptr = Pointer.fromAddress(0);
 
 /// Represents a pointer into the native C memory. Cannot be extended.
 @pragma("vm:entry-point")
 class Pointer<T extends NativeType> extends NativeType {
-  /// Allocate [count] elements of type [T] on the native heap via malloc() and
-  /// return a pointer to the newly allocated memory.
-  ///
-  /// Note that the memory is uninitialized.
-  external factory Pointer.allocate({int count: 1});
-
   /// Construction from raw integer.
   external factory Pointer.fromAddress(int ptr);
 
@@ -63,20 +58,6 @@
       @DartRepresentationOf("T") Function f,
       [Object exceptionalReturn]);
 
-  /// Store a Dart value into this location.
-  ///
-  /// The [value] is automatically marshalled into its native representation.
-  /// Note that ints which do not fit in [T] are truncated and sign extended,
-  /// and doubles stored into Pointer<[Float]> lose precision.
-  external void store(@DartRepresentationOf("T") Object value);
-
-  /// Load a Dart value from this location.
-  ///
-  /// The value is automatically unmarshalled from its native representation.
-  /// Loading a [Struct] reference returns a reference backed by native memory
-  /// (the same pointer as it's loaded from).
-  external R load<@DartRepresentationOf("T") R>();
-
   /// Access to the raw pointer value.
   /// On 32-bit systems, the upper 32-bits of the result are 0.
   external int get address;
@@ -84,11 +65,6 @@
   /// Pointer arithmetic (takes element size into account).
   external Pointer<T> elementAt(int index);
 
-  /// Pointer arithmetic (byte offset).
-  // TODO(dacoharkes): remove this?
-  // https://github.com/dart-lang/sdk/issues/35883
-  external Pointer<T> offsetBy(int offsetInBytes);
-
   /// Cast Pointer<T> to a Pointer<V>.
   external Pointer<U> cast<U extends NativeType>();
 
@@ -99,40 +75,6 @@
   /// invocations -- where the type of the receiver is [dynamic].
   external R asFunction<@DartRepresentationOf("T") R extends Function>();
 
-  /// Free memory on the C heap pointed to by this pointer with free().
-  ///
-  /// Note that this zeros out the address.
-  external void free();
-
-  /// Creates an *external* typed data array backed by this pointer.
-  ///
-  /// The typed data array returned is only valid for as long as the backing
-  /// [Pointer]. Accessing any element of the type data array after this
-  /// [Pointer] has been [Pointer.free()]d will cause undefined behavior.
-  ///
-  /// Since [Pointer]s do not know their length, the size of the typed data is
-  /// controlled by `count`, in units of the size of the native type for this
-  /// [Pointer] (similarly to [Pointer.allocate]).
-  ///
-  /// The kind of TypedData produced depends on the native type:
-  ///
-  ///   Pointer<Int8> -> Int8List
-  ///   Pointer<Uint8> -> Uint8List
-  ///   etc. up to Int64/Uint64
-  ///   Pointer<IntPtr> -> Int32List/Int64List depending on platform word size
-  ///   Pointer<Float> -> Float32List
-  ///   Pointer<Double> -> Float64List
-  ///
-  /// Creation of a [Uint8ClampedList] is not supported. Creation of a typed
-  /// data from a [Pointer] to any other native type is not supported.
-  ///
-  /// The pointer must be aligned to a multiple of the native type's size.
-  //
-  // TODO(37773): Use extension methods to articulate more precise return types.
-  // We should still keep this member though as a generic way to access a
-  // Pointer of unknown type.
-  external TypedData asExternalTypedData({int count: 1});
-
   /// Equality for Pointers only depends on their address.
   bool operator ==(other) {
     if (other == null) return false;
@@ -144,3 +86,528 @@
     return address.hashCode;
   }
 }
+
+//
+// The following code is generated, do not edit by hand.
+//
+// Code generated by `runtime/tools/ffi/sdk_lib_ffi_generator.dart`.
+//
+
+/// Extension on [Pointer] specialized for the type argument [Int8].
+extension Int8Pointer on Pointer<Int8> {
+  /// The 8-bit two's complement integer at [address].
+  ///
+  /// A Dart integer is truncated to 8 bits (as if by `.toSigned(8)`) before
+  /// being stored, and the 8-bit value is sign-extended when it is loaded.
+  external int get value;
+
+  /// The 8-bit two's complement integer at [address].
+  ///
+  /// A Dart integer is truncated to 8 bits (as if by `.toSigned(8)`) before
+  /// being stored, and the 8-bit value is sign-extended when it is loaded.
+  external void set value(int value);
+
+  /// The 8-bit two's complement integer at `address + index`.
+  ///
+  /// A Dart integer is truncated to 8 bits (as if by `.toSigned(8)`) before
+  /// being stored, and the 8-bit value is sign-extended when it is loaded.
+  external int operator [](int index);
+
+  /// The 8-bit two's complement integer at `address + index`.
+  ///
+  /// A Dart integer is truncated to 8 bits (as if by `.toSigned(8)`) before
+  /// being stored, and the 8-bit value is sign-extended when it is loaded.
+  external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Int8List asTypedList(int length);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Int16].
+extension Int16Pointer on Pointer<Int16> {
+  /// The 16-bit two's complement integer at [address].
+  ///
+  /// A Dart integer is truncated to 16 bits (as if by `.toSigned(16)`) before
+  /// being stored, and the 16-bit value is sign-extended when it is loaded.
+  ///
+  /// The [address] must be 2-byte aligned.
+  external int get value;
+
+  /// The 16-bit two's complement integer at [address].
+  ///
+  /// A Dart integer is truncated to 16 bits (as if by `.toSigned(16)`) before
+  /// being stored, and the 16-bit value is sign-extended when it is loaded.
+  ///
+  /// The [address] must be 2-byte aligned.
+  external void set value(int value);
+
+  /// The 16-bit two's complement integer at `address + 2 * index`.
+  ///
+  /// A Dart integer is truncated to 16 bits (as if by `.toSigned(16)`) before
+  /// being stored, and the 16-bit value is sign-extended when it is loaded.
+  ///
+  /// The [address] must be 2-byte aligned.
+  external int operator [](int index);
+
+  /// The 16-bit two's complement integer at `address + 2 * index`.
+  ///
+  /// A Dart integer is truncated to 16 bits (as if by `.toSigned(16)`) before
+  /// being stored, and the 16-bit value is sign-extended when it is loaded.
+  ///
+  /// The [address] must be 2-byte aligned.
+  external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + 2 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  ///
+  /// The [address] must be 2-byte aligned.
+  external Int16List asTypedList(int length);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Int32].
+extension Int32Pointer on Pointer<Int32> {
+  /// The 32-bit two's complement integer at [address].
+  ///
+  /// A Dart integer is truncated to 32 bits (as if by `.toSigned(32)`) before
+  /// being stored, and the 32-bit value is sign-extended when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external int get value;
+
+  /// The 32-bit two's complement integer at [address].
+  ///
+  /// A Dart integer is truncated to 32 bits (as if by `.toSigned(32)`) before
+  /// being stored, and the 32-bit value is sign-extended when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external void set value(int value);
+
+  /// The 32-bit two's complement integer at `address + 4 * index`.
+  ///
+  /// A Dart integer is truncated to 32 bits (as if by `.toSigned(32)`) before
+  /// being stored, and the 32-bit value is sign-extended when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external int operator [](int index);
+
+  /// The 32-bit two's complement integer at `address + 4 * index`.
+  ///
+  /// A Dart integer is truncated to 32 bits (as if by `.toSigned(32)`) before
+  /// being stored, and the 32-bit value is sign-extended when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + 4 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external Int32List asTypedList(int length);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Int64].
+extension Int64Pointer on Pointer<Int64> {
+  /// The 64-bit two's complement integer at [address].
+  ///
+  /// The [address] must be 8-byte aligned.
+  external int get value;
+
+  /// The 64-bit two's complement integer at [address].
+  ///
+  /// The [address] must be 8-byte aligned.
+  external void set value(int value);
+
+  /// The 64-bit two's complement integer at `address + 8 * index`.
+  ///
+  /// The [address] must be 8-byte aligned.
+  external int operator [](int index);
+
+  /// The 64-bit two's complement integer at `address + 8 * index`.
+  ///
+  /// The [address] must be 8-byte aligned.
+  external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + 8 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  ///
+  /// The [address] must be 8-byte aligned.
+  external Int64List asTypedList(int length);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Uint8].
+extension Uint8Pointer on Pointer<Uint8> {
+  /// The 8-bit unsigned integer at [address].
+  ///
+  /// A Dart integer is truncated to 8 bits (as if by `.toUnsigned(8)`) before
+  /// being stored, and the 8-bit value is zero-extended when it is loaded.
+  external int get value;
+
+  /// The 8-bit unsigned integer at [address].
+  ///
+  /// A Dart integer is truncated to 8 bits (as if by `.toUnsigned(8)`) before
+  /// being stored, and the 8-bit value is zero-extended when it is loaded.
+  external void set value(int value);
+
+  /// The 8-bit unsigned integer at `address + index`.
+  ///
+  /// A Dart integer is truncated to 8 bits (as if by `.toUnsigned(8)`) before
+  /// being stored, and the 8-bit value is zero-extended when it is loaded.
+  external int operator [](int index);
+
+  /// The 8-bit unsigned integer at `address + index`.
+  ///
+  /// A Dart integer is truncated to 8 bits (as if by `.toUnsigned(8)`) before
+  /// being stored, and the 8-bit value is zero-extended when it is loaded.
+  external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  external Uint8List asTypedList(int length);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Uint16].
+extension Uint16Pointer on Pointer<Uint16> {
+  /// The 16-bit unsigned integer at [address].
+  ///
+  /// A Dart integer is truncated to 16 bits (as if by `.toUnsigned(16)`) before
+  /// being stored, and the 16-bit value is zero-extended when it is loaded.
+  ///
+  /// The [address] must be 2-byte aligned.
+  external int get value;
+
+  /// The 16-bit unsigned integer at [address].
+  ///
+  /// A Dart integer is truncated to 16 bits (as if by `.toUnsigned(16)`) before
+  /// being stored, and the 16-bit value is zero-extended when it is loaded.
+  ///
+  /// The [address] must be 2-byte aligned.
+  external void set value(int value);
+
+  /// The 16-bit unsigned integer at `address + 2 * index`.
+  ///
+  /// A Dart integer is truncated to 16 bits (as if by `.toUnsigned(16)`) before
+  /// being stored, and the 16-bit value is zero-extended when it is loaded.
+  ///
+  /// The [address] must be 2-byte aligned.
+  external int operator [](int index);
+
+  /// The 16-bit unsigned integer at `address + 2 * index`.
+  ///
+  /// A Dart integer is truncated to 16 bits (as if by `.toUnsigned(16)`) before
+  /// being stored, and the 16-bit value is zero-extended when it is loaded.
+  ///
+  /// The [address] must be 2-byte aligned.
+  external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + 2 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  ///
+  /// The [address] must be 2-byte aligned.
+  external Uint16List asTypedList(int length);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Uint32].
+extension Uint32Pointer on Pointer<Uint32> {
+  /// The 32-bit unsigned integer at [address].
+  ///
+  /// A Dart integer is truncated to 32 bits (as if by `.toUnsigned(32)`) before
+  /// being stored, and the 32-bit value is zero-extended when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external int get value;
+
+  /// The 32-bit unsigned integer at [address].
+  ///
+  /// A Dart integer is truncated to 32 bits (as if by `.toUnsigned(32)`) before
+  /// being stored, and the 32-bit value is zero-extended when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external void set value(int value);
+
+  /// The 32-bit unsigned integer at `address + 4 * index`.
+  ///
+  /// A Dart integer is truncated to 32 bits (as if by `.toUnsigned(32)`) before
+  /// being stored, and the 32-bit value is zero-extended when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external int operator [](int index);
+
+  /// The 32-bit unsigned integer at `address + 4 * index`.
+  ///
+  /// A Dart integer is truncated to 32 bits (as if by `.toUnsigned(32)`) before
+  /// being stored, and the 32-bit value is zero-extended when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + 4 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external Uint32List asTypedList(int length);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Uint64].
+extension Uint64Pointer on Pointer<Uint64> {
+  /// The 64-bit unsigned integer at [address].
+  ///
+  /// The [address] must be 8-byte aligned.
+  external int get value;
+
+  /// The 64-bit unsigned integer at [address].
+  ///
+  /// The [address] must be 8-byte aligned.
+  external void set value(int value);
+
+  /// The 64-bit unsigned integer at `address + 8 * index`.
+  ///
+  /// The [address] must be 8-byte aligned.
+  external int operator [](int index);
+
+  /// The 64-bit unsigned integer at `address + 8 * index`.
+  ///
+  /// The [address] must be 8-byte aligned.
+  external void operator []=(int index, int value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + 8 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  ///
+  /// The [address] must be 8-byte aligned.
+  external Uint64List asTypedList(int length);
+}
+
+/// Extension on [Pointer] specialized for the type argument [IntPtr].
+extension IntPtrPointer on Pointer<IntPtr> {
+  /// The 32 or 64-bit two's complement integer at [address].
+  ///
+  /// On 32-bit platforms this is a 32-bit integer, and on 64-bit platforms
+  /// this is a 64-bit integer.
+  ///
+  /// On 32-bit platforms a Dart integer is truncated to 32 bits (as if by
+  /// `.toSigned(32)`) before being stored, and the 32-bit value is
+  /// sign-extended when it is loaded.
+  ///
+  /// On 32-bit platforms the [address] must be 4-byte aligned, and on 64-bit
+  /// platforms the [address] must be 8-byte aligned.
+  external int get value;
+
+  /// The 32 or 64-bit two's complement integer at [address].
+  ///
+  /// On 32-bit platforms this is a 32-bit integer, and on 64-bit platforms
+  /// this is a 64-bit integer.
+  ///
+  /// On 32-bit platforms a Dart integer is truncated to 32 bits (as if by
+  /// `.toSigned(32)`) before being stored, and the 32-bit value is
+  /// sign-extended when it is loaded.
+  ///
+  /// On 32-bit platforms the [address] must be 4-byte aligned, and on 64-bit
+  /// platforms the [address] must be 8-byte aligned.
+  external void set value(int value);
+
+  /// The 32 or 64-bit two's complement integer at `address + (4 or 8) * index`.
+  ///
+  /// On 32-bit platforms this is a 32-bit integer, and on 64-bit platforms
+  /// this is a 64-bit integer.
+  ///
+  /// On 32-bit platforms a Dart integer is truncated to 32 bits (as if by
+  /// `.toSigned(32)`) before being stored, and the 32-bit value is
+  /// sign-extended when it is loaded.
+  ///
+  /// On 32-bit platforms the [address] must be 4-byte aligned, and on 64-bit
+  /// platforms the [address] must be 8-byte aligned.
+  external int operator [](int index);
+
+  /// The 32 or 64-bit two's complement integer at `address + (4 or 8) * index`.
+  ///
+  /// On 32-bit platforms this is a 32-bit integer, and on 64-bit platforms
+  /// this is a 64-bit integer.
+  ///
+  /// On 32-bit platforms a Dart integer is truncated to 32 bits (as if by
+  /// `.toSigned(32)`) before being stored, and the 32-bit value is
+  /// sign-extended when it is loaded.
+  ///
+  /// On 32-bit platforms the [address] must be 4-byte aligned, and on 64-bit
+  /// platforms the [address] must be 8-byte aligned.
+  external void operator []=(int index, int value);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Float].
+extension FloatPointer on Pointer<Float> {
+  /// The float at [address].
+  ///
+  /// A Dart double loses precision before being stored, and the float value is
+  /// converted to a double when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external double get value;
+
+  /// The float at [address].
+  ///
+  /// A Dart double loses precision before being stored, and the float value is
+  /// converted to a double when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external void set value(double value);
+
+  /// The float at `address + 4 * index`.
+  ///
+  /// A Dart double loses precision before being stored, and the float value is
+  /// converted to a double when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external double operator [](int index);
+
+  /// The float at `address + 4 * index`.
+  ///
+  /// A Dart double loses precision before being stored, and the float value is
+  /// converted to a double when it is loaded.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external void operator []=(int index, double value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + 4 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  ///
+  /// The [address] must be 4-byte aligned.
+  external Float32List asTypedList(int length);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Double].
+extension DoublePointer on Pointer<Double> {
+  /// The double at [address].
+  ///
+  /// The [address] must be 8-byte aligned.
+  external double get value;
+
+  /// The double at [address].
+  ///
+  /// The [address] must be 8-byte aligned.
+  external void set value(double value);
+
+  /// The double at `address + 8 * index`.
+  ///
+  /// The [address] must be 8-byte aligned.
+  external double operator [](int index);
+
+  /// The double at `address + 8 * index`.
+  ///
+  /// The [address] must be 8-byte aligned.
+  external void operator []=(int index, double value);
+
+  /// Creates a typed list view backed by memory in the address space.
+  ///
+  /// The returned view will allow access to the memory range from [address]
+  /// to `address + 8 * length`.
+  ///
+  /// The user has to ensure the memory range is accessible while using the
+  /// returned list.
+  ///
+  /// The [address] must be 8-byte aligned.
+  external Float64List asTypedList(int length);
+}
+
+//
+// End of generated code.
+//
+
+/// Extension on [Pointer] specialized for the type argument [Pointer].
+extension PointerPointer<T extends NativeType> on Pointer<Pointer<T>> {
+  /// The pointer at [address].
+  ///
+  /// A [Pointer] is unboxed before being stored (as if by `.address`), and the
+  /// pointer is boxed (as if by `Pointer.fromAddress`) when loaded.
+  ///
+  /// On 32-bit platforms the [address] must be 4-byte aligned, and on 64-bit
+  /// platforms the [address] must be 8-byte aligned.
+  external Pointer<T> get value;
+
+  /// Store a Dart value into this location.
+  ///
+  /// A [Pointer] is unboxed before being stored (as if by `.address`), and the
+  /// pointer is boxed (as if by `Pointer.fromAddress`) when loaded.
+  ///
+  /// On 32-bit platforms the [address] must be 4-byte aligned, and on 64-bit
+  /// platforms the [address] must be 8-byte aligned.
+  external void set value(Pointer<T> value);
+
+  /// Load a Dart value from this location offset by [index].
+  ///
+  /// A [Pointer] is unboxed before being stored (as if by `.address`), and the
+  /// pointer is boxed (as if by `Pointer.fromAddress`) when loaded.
+  ///
+  /// On 32-bit platforms the [address] must be 4-byte aligned, and on 64-bit
+  /// platforms the [address] must be 8-byte aligned.
+  external Pointer<T> operator [](int index);
+
+  /// Store a Dart value into this location offset by [index].
+  ///
+  /// A [Pointer] is unboxed before being stored (as if by `.address`), and the
+  /// pointer is boxed (as if by `Pointer.fromAddress`) when loaded.
+  ///
+  /// On 32-bit platforms the [address] must be 4-byte aligned, and on 64-bit
+  /// platforms the [address] must be 8-byte aligned.
+  external void operator []=(int index, Pointer<T> value);
+}
+
+/// Extension on [Pointer] specialized for the type argument [Struct].
+extension StructPointer<T extends Struct> on Pointer<T> {
+  /// Creates a reference to access the fields of this struct backed by native
+  /// memory at [address].
+  ///
+  /// The [address] must be aligned according to the struct alignment rules of
+  /// the platform.
+  external T get ref;
+
+  /// Creates a reference to access the fields of this struct backed by native
+  /// memory at `address + sizeOf<T>() * index`.
+  ///
+  /// The [address] must be aligned according to the struct alignment rules of
+  /// the platform.
+  external T operator [](int index);
+}
diff --git a/sdk_nnbd/lib/ffi/struct.dart b/sdk_nnbd/lib/ffi/struct.dart
index 33872f3..326df67 100644
--- a/sdk_nnbd/lib/ffi/struct.dart
+++ b/sdk_nnbd/lib/ffi/struct.dart
@@ -17,12 +17,22 @@
 /// "@Int32()" for "int").
 ///
 /// Instances of a subclass of [Struct] have reference semantics and are backed
-/// by native memory. The may allocated via [Pointer.allocate] or loaded from a
+/// by native memory. The may allocated via allocation or loaded from a
 /// [Pointer], but not by a generative constructor.
-abstract class Struct<S extends NativeType> extends NativeType {
-  /// Returns the address backing the reference.
-  final Pointer<S> addressOf;
+abstract class Struct extends NativeType {
+  final Pointer<Struct> _addressOf;
 
-  Struct() : addressOf = null;
-  Struct.fromPointer(this.addressOf);
+  /// Construct a reference to the [nullptr].
+  ///
+  /// Use [StructPointer]'s `.ref` to gain references to native memory backed
+  /// structs.
+  Struct() : _addressOf = nullptr;
+
+  Struct._fromPointer(this._addressOf);
+}
+
+/// Extension on [Struct] specialized for it's subtypes.
+extension StructAddressOf<T extends Struct> on T {
+  /// Returns the address backing the reference.
+  Pointer<T> get addressOf => _addressOf as Pointer<T>;
 }
diff --git a/sdk_nnbd/lib/html/dart2js/html_dart2js.dart b/sdk_nnbd/lib/html/dart2js/html_dart2js.dart
index 64aa8ab..29f0c70 100644
--- a/sdk_nnbd/lib/html/dart2js/html_dart2js.dart
+++ b/sdk_nnbd/lib/html/dart2js/html_dart2js.dart
@@ -68,8 +68,9 @@
         getNativeInterceptor,
         setDispatchProperty;
 
-export 'dart:math' show Rectangle, Point;
 export 'dart:_internal' show HttpStatus;
+export 'dart:html_common' show promiseToFuture;
+export 'dart:math' show Rectangle, Point;
 
 /**
  * Top-level container for a web page, which is usually a browser tab or window.
@@ -92,33 +93,13 @@
 HtmlDocument get document =>
     JS('returns:HtmlDocument;depends:none;effects:none;gvn:true', 'document');
 
-// Supoort to convert JS Promise to a Dart Future.
-Future<T> promiseToFuture<T>(jsPromise) {
-  var completer = new Completer<T>();
-
-  var thenSuccessCode = (promiseValue) => completer.complete(promiseValue);
-  var thenErrorCode = (promiseError) => completer.completeError(promiseError);
-
-  JS("", "#.then(#, #)", jsPromise, convertDartClosureToJS(thenSuccessCode, 1),
-      convertDartClosureToJS(thenErrorCode, 1));
-
-  return completer.future;
-}
-
-// Supoort to convert JS Promise to a Dart Future<Map<String, dynamic>>.  Each property of the JS
-// object is added to the Map as a key of type String with a value of type dynamic.
-Future<Map<String, dynamic>> promiseToFutureAsMap(jsPromise) {
-  var completer = new Completer<Map<String, dynamic>>();
-
-  var thenSuccessCode = (promiseValue) =>
-      completer.complete(convertNativeToDart_Dictionary(promiseValue));
-  var thenErrorCode = (promiseError) => completer.completeError(promiseError);
-
-  JS("", "#.then(#, #)", jsPromise, convertDartClosureToJS(thenSuccessCode, 1),
-      convertDartClosureToJS(thenErrorCode, 1));
-
-  return completer.future;
-}
+/// Convert a JS Promise to a Future<Map<String, dynamic>>.
+///
+/// On a successful result the native JS result will be converted to a Dart Map.
+/// See [convertNativeToDart_Dictionary]. On a rejected promise the error is
+/// forwarded without change.
+Future<Map<String, dynamic>> promiseToFutureAsMap(jsPromise) =>
+    promiseToFuture(jsPromise).then(convertNativeToDart_Dictionary);
 
 // Workaround for tags like <cite> that lack their own Element subclass --
 // Dart issue 1990.
@@ -12635,7 +12616,7 @@
    * [timing] paramter can be a double, representing the number of milliseconds
    * for the transition, or a Map with fields corresponding to those
    * of the [Timing] object.
-  **/
+   */
   @SupportedBrowser(SupportedBrowser.CHROME, '36')
   Animation animate(Iterable<Map<String, dynamic>> frames, [timing]) {
     if (frames is! Iterable || !(frames.every((x) => x is Map))) {
diff --git a/sdk_nnbd/lib/html/html_common/conversions.dart b/sdk_nnbd/lib/html/html_common/conversions.dart
index 64c7cb8..8801eae 100644
--- a/sdk_nnbd/lib/html/html_common/conversions.dart
+++ b/sdk_nnbd/lib/html/html_common/conversions.dart
@@ -238,7 +238,7 @@
     }
 
     if (isJavaScriptPromise(e)) {
-      return convertNativePromiseToDartFuture(e);
+      return promiseToFuture(e);
     }
 
     if (isJavaScriptSimpleObject(e)) {
diff --git a/sdk_nnbd/lib/html/html_common/conversions_dart2js.dart b/sdk_nnbd/lib/html/html_common/conversions_dart2js.dart
index c973a55..b287be1 100644
--- a/sdk_nnbd/lib/html/html_common/conversions_dart2js.dart
+++ b/sdk_nnbd/lib/html/html_common/conversions_dart2js.dart
@@ -100,12 +100,11 @@
 bool isJavaScriptPromise(value) =>
     JS('bool', r'typeof Promise != "undefined" && # instanceof Promise', value);
 
-Future convertNativePromiseToDartFuture(promise) {
-  var completer = new Completer();
-  var then = convertDartClosureToJS((result) => completer.complete(result), 1);
-  var error =
-      convertDartClosureToJS((result) => completer.completeError(result), 1);
-  var newPromise = JS('', '#.then(#)["catch"](#)', promise, then, error);
+Future<T> promiseToFuture<T>(promise) {
+  var completer = new Completer<T>();
+  var then = convertDartClosureToJS((r) => completer.complete(r), 1);
+  var error = convertDartClosureToJS((e) => completer.completeError(e), 1);
+  JS('', '#.then(#, #)', promise, then, error);
   return completer.future;
 }
 
diff --git a/sdk_nnbd/lib/io/file_system_entity.dart b/sdk_nnbd/lib/io/file_system_entity.dart
index 871cfd9..e7b36e2 100644
--- a/sdk_nnbd/lib/io/file_system_entity.dart
+++ b/sdk_nnbd/lib/io/file_system_entity.dart
@@ -488,7 +488,9 @@
    *
    *   * The [Stream] is canceled, e.g. by calling `cancel` on the
    *      [StreamSubscription].
-   *   * The [FileSystemEntity] being watches, is deleted.
+   *   * The [FileSystemEntity] being watched, is deleted.
+   *   * System Watcher exits unexpectedly. e.g. On `Windows` this happens when
+   *     buffer that receive events from `ReadDirectoryChangesW` overflows.
    *
    * Use `events` to specify what events to listen for. The constants in
    * [FileSystemEvent] can be or'ed together to mix events. Default is
diff --git a/sdk_nnbd/lib/isolate/isolate.dart b/sdk_nnbd/lib/isolate/isolate.dart
index 11240ad..60d66af 100644
--- a/sdk_nnbd/lib/isolate/isolate.dart
+++ b/sdk_nnbd/lib/isolate/isolate.dart
@@ -626,8 +626,7 @@
    * In the special circumstances when two isolates share the same code and are
    * running in the same process (e.g. isolates created via [Isolate.spawn]), it
    * is also possible to send object instances (which would be copied in the
-   * process). This is currently only supported by the dartvm.  For now, the
-   * dart2js compiler only supports the restricted messages described above.
+   * process). This is currently only supported by the dart vm.
    *
    * The send happens immediately and doesn't block.  The corresponding receive
    * port can receive the message as soon as its isolate's event loop is ready
diff --git a/sdk_nnbd/lib/mirrors/mirrors.dart b/sdk_nnbd/lib/mirrors/mirrors.dart
index ee68e01..ec27699 100644
--- a/sdk_nnbd/lib/mirrors/mirrors.dart
+++ b/sdk_nnbd/lib/mirrors/mirrors.dart
@@ -1073,6 +1073,11 @@
   bool get isFactoryConstructor;
 
   /**
+   * Is the reflectee an extension method?
+   */
+  bool get isExtensionMember;
+
+  /**
    * Whether this mirror is equal to [other].
    *
    * The equality holds if and only if
@@ -1114,6 +1119,11 @@
   bool get isConst;
 
   /**
+   * Is the reflectee an extension member?
+   */
+  bool get isExtensionMember;
+
+  /**
    * Whether this mirror is equal to [other].
    *
    * The equality holds if and only if
diff --git a/tests/co19_2/update.sh b/tests/co19_2/update.sh
index 2003de1..3fb0933 100755
--- a/tests/co19_2/update.sh
+++ b/tests/co19_2/update.sh
@@ -15,7 +15,7 @@
 git clone https://dart.googlesource.com/co19 tests/co19_2/src.git
 CO19=tests/co19_2/src.git
 OLD=$(gclient getdep --var=co19_2_rev)
-NEW=$(cd $CO19 && git fetch origin && git rev-parse origin/master)
+NEW=$(cd $CO19 && git fetch origin && git rev-parse origin/pre-nnbd)
 
 git fetch origin
 git branch cl-co19-roll-co19-to-$NEW origin/master
@@ -57,7 +57,7 @@
                 tools/bots/test_matrix.json \
              | tr -d '[",]')
 
-git cl try -B luci.dart.try $(for BUILDER in $BUILDERS; do echo -b $BUILDER-try; done)
+git cl try -B dart/try $(for BUILDER in $BUILDERS; do echo -b $BUILDER-try; done)
 
 git cl web
 
diff --git a/tests/compiler/dart2js/rti/emission/list.dart b/tests/compiler/dart2js/rti/emission/list.dart
index 14d539bf..72f7d54 100644
--- a/tests/compiler/dart2js/rti/emission/list.dart
+++ b/tests/compiler/dart2js/rti/emission/list.dart
@@ -7,11 +7,11 @@
 
 /*class: global#Iterable:checkedInstance*/
 
-/*strong.class: A:checkedTypeArgument,checks=[],typeArgument*/
+/*strong.class: A:checkedInstance,checkedTypeArgument,checks=[],typeArgument*/
 /*omit.class: A:checkedTypeArgument,checks=[],typeArgument*/
 class A {}
 
-/*strong.class: B:checks=[],typeArgument*/
+/*strong.class: B:checkedInstance,checks=[],typeArgument*/
 /*omit.class: B:checks=[],typeArgument*/
 class B {}
 
diff --git a/tests/compiler/dartdevc/modular/nnbd_subtype/main.dart b/tests/compiler/dartdevc/modular/nnbd_subtype/main.dart
index fd89ae0..d03c305 100644
--- a/tests/compiler/dartdevc/modular/nnbd_subtype/main.dart
+++ b/tests/compiler/dartdevc/modular/nnbd_subtype/main.dart
@@ -21,7 +21,7 @@
 class F extends E<B, B> {}
 
 // Returns sWrapped<tWrapped> as a wrapped type.
-Object generic1(Type sWrapped, Type tWrapped) {
+Type generic1(Type sWrapped, Type tWrapped) {
   var s = dart.unwrapType(sWrapped);
   var t = dart.unwrapType(tWrapped);
   var sGeneric = dart.getGenericClass(s);
@@ -29,7 +29,7 @@
 }
 
 // Returns sWrapped<tWrapped, rWrapped> as a wrapped type.
-Object generic2(Type sWrapped, Type tWrapped, Type rWrapped) {
+Type generic2(Type sWrapped, Type tWrapped, Type rWrapped) {
   var s = dart.unwrapType(sWrapped);
   var t = dart.unwrapType(tWrapped);
   var r = dart.unwrapType(rWrapped);
@@ -38,7 +38,7 @@
 }
 
 // Returns a function type of argWrapped -> returnWrapped as a wrapped type.
-Object function1(Type returnWrapped, Type argWrapped) {
+Type function1(Type returnWrapped, Type argWrapped) {
   var returnType = dart.unwrapType(returnWrapped);
   var argType = dart.unwrapType(argWrapped);
   var fun = dart.fnType(returnType, [argType]);
@@ -47,12 +47,12 @@
 
 // Returns a function type with a bounded type argument that takes no argument
 // and returns void as a wrapped type.
-Object genericFunction(Type boundWrapped) => dart.wrapType(dart.gFnType(
+Type genericFunction(Type boundWrapped) => dart.wrapType(dart.gFnType(
     (T) => [dart.VoidType, []], (T) => [dart.unwrapType(boundWrapped)]));
 
 // Returns a function type with a bounded generic return type of
 // <T extends typeBoud> argWrapped -> T as a wrapped type.
-Object functionGenericReturn(Type boundWrapped, Type argWrapped) =>
+Type functionGenericReturn(Type boundWrapped, Type argWrapped) =>
     dart.wrapType(dart.gFnType(
         (T) => [
               T,
@@ -62,7 +62,7 @@
 
 // Returns a function with a bounded generic argument type of
 // <T extends typeBoud> T -> returnWrapped as a wrapped type.
-Object functionGenericArg(Type boundWrapped, Type returnWrapped) =>
+Type functionGenericArg(Type boundWrapped, Type returnWrapped) =>
     dart.wrapType(dart.gFnType(
         (T) => [
               dart.unwrapType(returnWrapped),
@@ -80,30 +80,52 @@
   var s = dart.unwrapType(sWrapped);
   var t = dart.unwrapType(tWrapped);
   Expect.isTrue(dart.isSubtypeOf(s, t), '$s should be subtype of $t.');
-  Expect.isFalse(dart.isSubtypeOf(t, s), '$t should not be subtype of $s.');
+  checkSubtypeFailure(tWrapped, sWrapped);
+}
+
+void checkSubtypeFailure(Type sWrapped, Type tWrapped) {
+  var s = dart.unwrapType(sWrapped);
+  var t = dart.unwrapType(tWrapped);
+  Expect.isFalse(dart.isSubtypeOf(s, t), '$s should not be subtype of $t.');
+}
+
+// NNBD tests
+// Returns tWrapped? as a wrapped type.
+Type nullable(Type tWrapped) {
+  var t = dart.unwrapType(tWrapped);
+  var tNullable = dart.nullable(t);
+  return dart.wrapType(tNullable);
+}
+
+// Returns tWrapped* as a wrapped type.
+Type legacy(Type tWrapped) {
+  var t = dart.unwrapType(tWrapped);
+  var tLegacy = dart.legacy(t);
+  return dart.wrapType(tLegacy);
 }
 
 void main() {
+  // dynamic <\: A
+  checkSubtypeFailure(dynamic, A);
   // A <: dynamic
   checkProperSubtype(A, dynamic);
-  // A <: Object
-  checkProperSubtype(A, Object);
-  // TODO(nshahan) Test void as top? A <: void
+  // A <: void
+  checkProperSubtype(A, dart.wrapType(dart.void_));
+  // Null <\: A
+  checkSubtypeFailure(Null, A);
 
-  // Null <: A
-  checkProperSubtype(Null, A);
-
-  // FutureOr<Null> <: Future<Null>
-  checkSubtype(generic1(FutureOr, Null), generic1(Future, Null));
+  // FutureOr<Never> <: Future<Never>
+  checkSubtype(generic1(FutureOr, dart.wrapType(dart.never_)),
+      generic1(Future, dart.wrapType(dart.never_)));
   // Future<B> <: FutureOr<A>
   checkProperSubtype(generic1(Future, B), generic1(FutureOr, A));
   // B <: <: FutureOr<A>
   checkProperSubtype(B, generic1(FutureOr, A));
   // Future<B> <: Future<A>
   checkProperSubtype(generic1(Future, B), generic1(Future, A));
+
   // B <: A
   checkProperSubtype(B, A);
-
   // A <: A
   checkSubtype(A, A);
   // C <: B
@@ -202,4 +224,51 @@
   checkProperSubtype(generic2(E, B, B), E);
   // // E<B, B> <: E<A, A>
   checkProperSubtype(generic2(E, B, B), generic2(E, A, A));
+
+  // A <: A?
+  checkProperSubtype(A, nullable(A));
+  // B <: A?
+  checkProperSubtype(B, nullable(A));
+  // C <: A?
+  checkProperSubtype(C, nullable(A));
+  // B? <: A?
+  checkProperSubtype(nullable(B), nullable(A));
+  // C? <: A?
+  checkProperSubtype(nullable(C), nullable(A));
+
+  // A <: Object
+  checkProperSubtype(A, Object);
+  // A* <: Object
+  checkProperSubtype(legacy(A), Object);
+  // dynamic <\: Object
+  checkSubtypeFailure(dynamic, Object);
+  // void <\: Object
+  checkSubtypeFailure(dart.wrapType(dart.void_), Object);
+  // Null <\: Object
+  checkSubtypeFailure(Null, Object);
+  // A? <\: Object
+  checkSubtypeFailure(nullable(A), Object);
+
+  // Null <: FutureOr<A?>
+  checkProperSubtype(Null, generic1(FutureOr, nullable(A)));
+  // Null <: Null
+  checkSubtype(Null, Null);
+  // Null <: A?
+  checkProperSubtype(Null, nullable(A));
+  // Null <: A*
+  checkProperSubtype(Null, legacy(A));
+
+  // B* <: A
+  checkProperSubtype(legacy(B), A);
+  // A* <\: B
+  checkSubtypeFailure(legacy(A), B);
+
+  // B? <: A*
+  checkProperSubtype(nullable(B), legacy(A));
+  // B <: A*
+  checkProperSubtype(B, legacy(A));
+  // A <: B*
+  checkSubtypeFailure(A, legacy(B));
+  // A? <: B*
+  checkSubtypeFailure(nullable(A), legacy(B));
 }
diff --git a/tests/compiler/dartdevc/modular/nnbd_subtype/modules.yaml b/tests/compiler/dartdevc/modular/nnbd_subtype/modules.yaml
index 4843548..0d34072 100644
--- a/tests/compiler/dartdevc/modular/nnbd_subtype/modules.yaml
+++ b/tests/compiler/dartdevc/modular/nnbd_subtype/modules.yaml
@@ -7,5 +7,5 @@
 # nnbd.
 dependencies:
   main: expect
-# flags:
-#   - non-nullable
\ No newline at end of file
+flags:
+  - non-nullable
\ No newline at end of file
diff --git a/tests/ffi/aliasing_test.dart b/tests/ffi/aliasing_test.dart
index 0413d8e..9ae36e8 100644
--- a/tests/ffi/aliasing_test.dart
+++ b/tests/ffi/aliasing_test.dart
@@ -12,9 +12,10 @@
 
 import 'dart:ffi';
 
+import "package:ffi/ffi.dart";
 import "package:expect/expect.dart";
 
-import 'dylib_utils.dart';
+import 'ffi_test_helpers.dart';
 
 void main() {
   for (int i = 0; i < 100; ++i) {
@@ -36,168 +37,166 @@
 }
 
 void testNonAlias() {
-  final source = Pointer<Int64>.allocate();
-  source.store(42);
-  final int a = source.load();
-  source.store(1984);
-  // alias.load() should be re-executed, as we wrote to alias.
-  Expect.notEquals(a, source.load<int>());
-  source.free();
+  final source = allocate<Int64>();
+  source.value = 42;
+  final int a = source.value;
+  source.value = 1984;
+  // alias.value should be re-executed, as we wrote to alias.
+  Expect.notEquals(a, source.value);
+  free(source);
 }
 
 void testAliasCast() {
-  final source = Pointer<Int64>.allocate();
+  final source = allocate<Int64>();
   final alias = source.cast<Int8>().cast<Int64>();
-  source.store(42);
-  final int a = source.load();
-  alias.store(1984);
-  // source.load() should be re-executed, we wrote alias which aliases source.
-  Expect.notEquals(a, source.load<int>());
-  source.free();
+  source.value = 42;
+  final int a = source.value;
+  alias.value = 1984;
+  // source.value should be re-executed, we wrote alias which aliases source.
+  Expect.notEquals(a, source.value);
+  free(source);
 }
 
 void testAliasCast2() {
-  final source = Pointer<Int64>.allocate();
+  final source = allocate<Int64>();
   final alias = source.cast<Int16>().cast<Int64>();
   final alias2 = source.cast<Int8>().cast<Int64>();
-  alias.store(42);
-  final int a = alias.load();
-  alias2.store(1984);
-  // alias.load() should be re-executed, we wrote alias2 which aliases alias.
-  Expect.notEquals(a, alias.load<int>());
-  source.free();
+  alias.value = 42;
+  final int a = alias.value;
+  alias2.value = 1984;
+  // alias.value should be re-executed, we wrote alias2 which aliases alias.
+  Expect.notEquals(a, alias.value);
+  free(source);
 }
 
 void testAliasOffsetBy() {
-  final source = Pointer<Int64>.allocate(count: 2);
+  final source = allocate<Int64>(count: 2);
   final alias = source.offsetBy(8).offsetBy(-8);
-  source.store(42);
-  final int a = source.load();
-  alias.store(1984);
-  // source.load() should be re-executed, we wrote alias which aliases source.
-  Expect.notEquals(a, source.load<int>());
-  source.free();
+  source.value = 42;
+  final int a = source.value;
+  alias.value = 1984;
+  // source.value should be re-executed, we wrote alias which aliases source.
+  Expect.notEquals(a, source.value);
+  free(source);
 }
 
 void testAliasOffsetBy2() {
-  final source = Pointer<Int64>.allocate(count: 3);
+  final source = allocate<Int64>(count: 3);
   final alias = source.offsetBy(16).offsetBy(-16);
   final alias2 = source.offsetBy(8).offsetBy(-8);
-  alias.store(42);
-  final int a = alias.load();
-  alias2.store(1984);
-  // alias.load() should be re-executed, we wrote alias2 which aliases alias.
-  Expect.notEquals(a, alias.load<int>());
-  source.free();
+  alias.value = 42;
+  final int a = alias.value;
+  alias2.value = 1984;
+  // alias.value should be re-executed, we wrote alias2 which aliases alias.
+  Expect.notEquals(a, alias.value);
+  free(source);
 }
 
 void testAliasElementAt() {
-  final source = Pointer<Int64>.allocate(count: 2);
+  final source = allocate<Int64>(count: 2);
   final alias = source.elementAt(1).elementAt(-1);
-  source.store(42);
-  final int a = source.load();
-  alias.store(1984);
-  // source.load() should be re-executed, we wrote alias which aliases source.
-  Expect.notEquals(a, source.load<int>());
-  source.free();
+  source.value = 42;
+  final int a = source.value;
+  alias.value = 1984;
+  // source.value should be re-executed, we wrote alias which aliases source.
+  Expect.notEquals(a, source.value);
+  free(source);
 }
 
 void testAliasElementAt2() {
-  final source = Pointer<Int64>.allocate(count: 3);
+  final source = allocate<Int64>(count: 3);
   final alias = source.elementAt(2).elementAt(-2);
   final alias2 = source.elementAt(1).elementAt(-1);
-  alias.store(42);
-  final int a = alias.load();
-  alias2.store(1984);
-  // alias.load() should be re-executed, we wrote alias2 which aliases alias.
-  Expect.notEquals(a, alias.load<int>());
-  source.free();
+  alias.value = 42;
+  final int a = alias.value;
+  alias2.value = 1984;
+  // alias.value should be re-executed, we wrote alias2 which aliases alias.
+  Expect.notEquals(a, alias.value);
+  free(source);
 }
 
 void testAliasFromAddress() {
-  final source = Pointer<Int64>.allocate();
+  final source = allocate<Int64>();
   final alias = Pointer<Int64>.fromAddress(source.address);
-  source.store(42);
-  final int a = source.load();
-  alias.store(1984);
-  // source.load() should be re-executed, we wrote alias which aliases source.
-  Expect.notEquals(a, source.load<int>());
-  source.free();
+  source.value = 42;
+  final int a = source.value;
+  alias.value = 1984;
+  // source.value should be re-executed, we wrote alias which aliases source.
+  Expect.notEquals(a, source.value);
+  free(source);
 }
 
 void testAliasFromAddress2() {
-  final source = Pointer<Int64>.allocate();
+  final source = allocate<Int64>();
   final alias = Pointer<Int64>.fromAddress(source.address);
   final alias2 = Pointer<Int64>.fromAddress(source.address);
-  alias.store(42);
-  final int a = alias.load();
-  alias2.store(1984);
-  // alias.load() should be re-executed, we wrote alias2 which aliases alias.
-  Expect.notEquals(a, alias.load<int>());
-  source.free();
+  alias.value = 42;
+  final int a = alias.value;
+  alias2.value = 1984;
+  // alias.value should be re-executed, we wrote alias2 which aliases alias.
+  Expect.notEquals(a, alias.value);
+  free(source);
 }
 
 void testAliasFromAddressViaMemory() {
-  final helper = Pointer<IntPtr>.allocate();
-  final source = Pointer<Int64>.allocate();
-  helper.store(source.address);
-  final alias = Pointer<Int64>.fromAddress(helper.load());
-  source.store(42);
-  final int a = source.load();
-  alias.store(1984);
-  // source.load() should be re-executed, we wrote alias which aliases source.
-  Expect.notEquals(a, source.load<int>());
-  helper.free();
-  source.free();
+  final helper = allocate<IntPtr>();
+  final source = allocate<Int64>();
+  helper.value = source.address;
+  final alias = Pointer<Int64>.fromAddress(helper.value);
+  source.value = 42;
+  final int a = source.value;
+  alias.value = 1984;
+  // source.value should be re-executed, we wrote alias which aliases source.
+  Expect.notEquals(a, source.value);
+  free(helper);
+  free(source);
 }
 
 void testAliasFromAddressViaMemory2() {
-  final helper = Pointer<IntPtr>.allocate();
-  final source = Pointer<Int64>.allocate();
-  helper.store(source.address);
-  final alias = Pointer<Int64>.fromAddress(helper.load());
-  final alias2 = Pointer<Int64>.fromAddress(helper.load());
-  alias.store(42);
-  final int a = alias.load();
-  alias2.store(1984);
-  // alias.load() should be re-executed, we wrote alias2 which aliases alias.
-  Expect.notEquals(a, alias.load<int>());
-  helper.free();
-  source.free();
+  final helper = allocate<IntPtr>();
+  final source = allocate<Int64>();
+  helper.value = source.address;
+  final alias = Pointer<Int64>.fromAddress(helper.value);
+  final alias2 = Pointer<Int64>.fromAddress(helper.value);
+  alias.value = 42;
+  final int a = alias.value;
+  alias2.value = 1984;
+  // alias.value should be re-executed, we wrote alias2 which aliases alias.
+  Expect.notEquals(a, alias.value);
+  free(helper);
+  free(source);
 }
 
 typedef NativeQuadOpSigned = Int64 Function(Int8, Int16, Int32, Int64);
 typedef QuadOp = int Function(int, int, int, int);
 
-DynamicLibrary ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
-
 QuadOp intComputation = ffiTestFunctions
     .lookupFunction<NativeQuadOpSigned, QuadOp>("IntComputation");
 
 void testAliasFromAddressViaNativeFunction() {
-  final source = Pointer<Int64>.allocate();
+  final source = allocate<Int64>();
   final alias =
       Pointer<Int64>.fromAddress(intComputation(0, 0, 0, source.address));
-  source.store(42);
-  final int a = source.load();
-  alias.store(1984);
-  // source.load() should be re-executed, we wrote alias which aliases source.
-  Expect.notEquals(a, source.load<int>());
-  source.free();
+  source.value = 42;
+  final int a = source.value;
+  alias.value = 1984;
+  // source.value should be re-executed, we wrote alias which aliases source.
+  Expect.notEquals(a, source.value);
+  free(source);
 }
 
 void testAliasFromAddressViaNativeFunction2() {
-  final source = Pointer<Int64>.allocate();
+  final source = allocate<Int64>();
   final alias =
       Pointer<Int64>.fromAddress(intComputation(0, 0, 0, source.address));
   final alias2 =
       Pointer<Int64>.fromAddress(intComputation(0, 0, 0, source.address));
-  alias.store(42);
-  final int a = alias.load();
-  alias2.store(1984);
-  // alias.load() should be re-executed, we wrote alias2 which aliases alias.
-  Expect.notEquals(a, alias.load<int>());
-  source.free();
+  alias.value = 42;
+  final int a = alias.value;
+  alias2.value = 1984;
+  // alias.value should be re-executed, we wrote alias2 which aliases alias.
+  Expect.notEquals(a, alias.value);
+  free(source);
 }
 
 @pragma('vm:never-inline')
@@ -205,11 +204,11 @@
     source.offsetBy(7).cast<Int8>();
 
 testPartialOverlap() {
-  final source = Pointer<Int64>.allocate(count: 2);
+  final source = allocate<Int64>(count: 2);
   final derived = makeDerived(source);
-  source.store(0x1122334455667788);
-  final int value = source.load();
-  derived.store(0xaa);
-  Expect.notEquals(value, source.load<int>());
-  source.free();
+  source.value = 0x1122334455667788;
+  final int value = source.value;
+  derived.value = 0xaa;
+  Expect.notEquals(value, source.value);
+  free(source);
 }
diff --git a/tests/ffi/coordinate.dart b/tests/ffi/coordinate.dart
index dbe0f3e..92dd9d4 100644
--- a/tests/ffi/coordinate.dart
+++ b/tests/ffi/coordinate.dart
@@ -5,9 +5,10 @@
 library FfiTest;
 
 import 'dart:ffi';
+import "package:ffi/ffi.dart";
 
 /// Sample struct for dart:ffi library.
-class Coordinate extends Struct<Coordinate> {
+class Coordinate extends Struct {
   @Double()
   double x;
 
@@ -17,7 +18,7 @@
   Pointer<Coordinate> next;
 
   factory Coordinate.allocate(double x, double y, Pointer<Coordinate> next) {
-    return Pointer<Coordinate>.allocate().load<Coordinate>()
+    return allocate<Coordinate>().ref
       ..x = x
       ..y = y
       ..next = next;
diff --git a/tests/ffi/coordinate_bare.dart b/tests/ffi/coordinate_bare.dart
index 83d5d4b..daaea24 100644
--- a/tests/ffi/coordinate_bare.dart
+++ b/tests/ffi/coordinate_bare.dart
@@ -7,7 +7,7 @@
 import 'dart:ffi';
 
 /// Stripped down sample struct for dart:ffi library.
-class Coordinate extends Struct<Coordinate> {
+class Coordinate extends Struct {
   @Double()
   double x;
 
diff --git a/tests/ffi/data_not_asan_test.dart b/tests/ffi/data_not_asan_test.dart
index 308c458..aa9cf24 100644
--- a/tests/ffi/data_not_asan_test.dart
+++ b/tests/ffi/data_not_asan_test.dart
@@ -9,9 +9,9 @@
 
 library FfiTest;
 
-import 'dart:ffi' as ffi;
-import 'dart:ffi' show Pointer;
+import 'dart:ffi';
 
+import "package:ffi/ffi.dart";
 import "package:expect/expect.dart";
 
 void main() {
@@ -22,16 +22,16 @@
 void testPointerAllocateTooLarge() {
   // Try to allocate something that doesn't fit in 64 bit address space.
   int maxInt = 9223372036854775807; // 2^63 - 1
-  Expect.throws(() => Pointer<ffi.Int64>.allocate(count: maxInt));
+  Expect.throws(() => allocate<Int64>(count: maxInt));
 
   // Try to allocate almost the full 64 bit address space.
   int maxInt1_8 = 1152921504606846975; // 2^60 -1
-  Expect.throws(() => Pointer<ffi.Int64>.allocate(count: maxInt1_8));
+  Expect.throws(() => allocate<Int64>(count: maxInt1_8));
 }
 
 void testPointerAllocateNegative() {
   // Passing in -1 will be converted into an unsigned integer. So, it will try
   // to allocate SIZE_MAX - 1 + 1 bytes. This will fail as it is the max amount
   // of addressable memory on the system.
-  Expect.throws(() => Pointer<ffi.Int8>.allocate(count: -1));
+  Expect.throws(() => allocate<Int8>(count: -1));
 }
diff --git a/tests/ffi/data_test.dart b/tests/ffi/data_test.dart
index a86f9af..3df6451 100644
--- a/tests/ffi/data_test.dart
+++ b/tests/ffi/data_test.dart
@@ -3,13 +3,17 @@
 // BSD-style license that can be found in the LICENSE file.
 //
 // Dart test program for testing dart:ffi primitive data pointers.
+//
+// SharedObjects=ffi_test_functions
 
 library FfiTest;
 
-import 'dart:ffi' as ffi;
-import 'dart:ffi' show Pointer;
+import 'dart:ffi';
 
 import "package:expect/expect.dart";
+import "package:ffi/ffi.dart";
+
+import 'ffi_test_helpers.dart';
 
 void main() {
   testPointerBasic();
@@ -51,46 +55,48 @@
   testSizeOfVoid();
   testSizeOfNativeFunction();
   testSizeOfNativeType();
-  testFreeZeroOut();
+  testDynamicInvocation();
+  testMemoryAddressTruncation();
+  testNullptrCast();
 }
 
 void testPointerBasic() {
-  Pointer<ffi.Int64> p = Pointer.allocate();
-  p.store(42);
-  Expect.equals(42, p.load<int>());
-  p.free();
+  Pointer<Int64> p = allocate();
+  p.value = 42;
+  Expect.equals(42, p.value);
+  free(p);
 }
 
 void testPointerFromPointer() {
-  Pointer<ffi.Int64> p = Pointer.allocate();
-  p.store(1337);
+  Pointer<Int64> p = allocate();
+  p.value = 1337;
   int ptr = p.address;
-  Pointer<ffi.Int64> p2 = Pointer.fromAddress(ptr);
-  Expect.equals(1337, p2.load<int>());
-  p.free();
+  Pointer<Int64> p2 = Pointer.fromAddress(ptr);
+  Expect.equals(1337, p2.value);
+  free(p);
 }
 
 void testPointerPointerArithmetic() {
-  Pointer<ffi.Int64> p = Pointer.allocate(count: 2);
-  Pointer<ffi.Int64> p2 = p.elementAt(1);
-  p2.store(100);
-  Pointer<ffi.Int64> p3 = p.offsetBy(8);
-  Expect.equals(100, p3.load<int>());
-  p.free();
+  Pointer<Int64> p = allocate(count: 2);
+  Pointer<Int64> p2 = p.elementAt(1);
+  p2.value = 100;
+  Pointer<Int64> p3 = p.offsetBy(8);
+  Expect.equals(100, p3.value);
+  free(p);
 }
 
 void testPointerPointerArithmeticSizes() {
-  Pointer<ffi.Int64> p = Pointer.allocate(count: 2);
-  Pointer<ffi.Int64> p2 = p.elementAt(1);
+  Pointer<Int64> p = allocate(count: 2);
+  Pointer<Int64> p2 = p.elementAt(1);
   int addr = p.address;
   Expect.equals(addr + 8, p2.address);
-  p.free();
+  free(p);
 
-  Pointer<ffi.Int32> p3 = Pointer.allocate(count: 2);
-  Pointer<ffi.Int32> p4 = p3.elementAt(1);
+  Pointer<Int32> p3 = allocate(count: 2);
+  Pointer<Int32> p4 = p3.elementAt(1);
   addr = p3.address;
   Expect.equals(addr + 4, p4.address);
-  p3.free();
+  free(p3);
 }
 
 void testPointerAllocateZero() {
@@ -100,309 +106,306 @@
   //
   // Null pointer throws a Dart exception.
   bool returnedNullPointer = false;
-  ffi.Pointer<ffi.Int8> p;
+  Pointer<Int8> p;
   try {
-    p = Pointer<ffi.Int8>.allocate(count: 0);
+    p = allocate<Int8>(count: 0);
   } on Exception {
     returnedNullPointer = true;
   }
   if (!returnedNullPointer) {
-    p.free();
+    free(p);
   }
 }
 
 void testPointerCast() {
-  Pointer<ffi.Int64> p = Pointer.allocate();
-  Pointer<ffi.Int32> p2 = p.cast(); // gets the correct type args back
-  p.free();
+  Pointer<Int64> p = allocate();
+  p.cast<Int32>(); // gets the correct type args back
+  free(p);
 }
 
 void testCastGeneric() {
-  Pointer<T> generic<T extends ffi.NativeType>(Pointer<ffi.Int16> p) {
+  Pointer<T> generic<T extends NativeType>(Pointer<Int16> p) {
     return p.cast();
   }
 
-  Pointer<ffi.Int16> p = Pointer.allocate();
-  Pointer<ffi.Int64> p2 = generic(p);
-  p.free();
+  Pointer<Int16> p = allocate();
+  Pointer<Int64> p2 = generic(p);
+  free(p);
 }
 
 void testCastGeneric2() {
-  Pointer<ffi.Int64> generic<T extends ffi.NativeType>(Pointer<T> p) {
+  Pointer<Int64> generic<T extends NativeType>(Pointer<T> p) {
     return p.cast();
   }
 
-  Pointer<ffi.Int16> p = Pointer.allocate();
-  Pointer<ffi.Int64> p2 = generic(p);
-  p.free();
+  Pointer<Int16> p = allocate();
+  Pointer<Int64> p2 = generic(p);
+  free(p);
 }
 
 void testCastNativeType() {
-  ffi.Pointer<ffi.Int64> p = Pointer.allocate();
-  p.cast<ffi.Pointer>();
-  p.free();
+  Pointer<Int64> p = allocate();
+  p.cast<Pointer>();
+  free(p);
 }
 
 void testCondensedNumbersInt8() {
-  ffi.Pointer<ffi.Int8> p = Pointer.allocate(count: 8);
+  Pointer<Int8> p = allocate(count: 8);
   for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
-    p.elementAt(i).store(i * 3);
+    p[i] = i * 3;
   }
   for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
-    Expect.equals(i * 3, p.elementAt(i).load<int>());
+    Expect.equals(i * 3, p[i]);
   }
-  p.free();
+  free(p);
 }
 
 void testCondensedNumbersFloat() {
-  ffi.Pointer<ffi.Float> p = Pointer.allocate(count: 8);
+  Pointer<Float> p = allocate(count: 8);
   for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
-    p.elementAt(i).store(1.511366173271439e-13);
+    p[i] = 1.511366173271439e-13;
   }
   for (var i in [0, 1, 2, 3, 4, 5, 6, 7]) {
-    Expect.equals(1.511366173271439e-13, p.elementAt(i).load<double>());
+    Expect.equals(1.511366173271439e-13, p[i]);
   }
-  p.free();
+  free(p);
 }
 
 void testRangeInt8() {
-  ffi.Pointer<ffi.Int8> p = Pointer.allocate();
-  p.store(127);
-  Expect.equals(127, p.load<int>());
-  p.store(-128);
-  Expect.equals(-128, p.load<int>());
+  Pointer<Int8> p = allocate();
+  p.value = 127;
+  Expect.equals(127, p.value);
+  p.value = -128;
+  Expect.equals(-128, p.value);
 
   Expect.equals(0x0000000000000080, 128);
   Expect.equals(0xFFFFFFFFFFFFFF80, -128);
-  p.store(128);
-  Expect.equals(-128, p.load<int>()); // truncated and sign extended
+  p.value = 128;
+  Expect.equals(-128, p.value); // truncated and sign extended
 
   Expect.equals(0xFFFFFFFFFFFFFF7F, -129);
   Expect.equals(0x000000000000007F, 127);
-  p.store(-129);
-  Expect.equals(127, p.load<int>()); // truncated
-  p.free();
+  p.value = -129;
+  Expect.equals(127, p.value); // truncated
+  free(p);
 }
 
 void testRangeUint8() {
-  ffi.Pointer<ffi.Uint8> p = Pointer.allocate();
-  p.store(255);
-  Expect.equals(255, p.load<int>());
-  p.store(0);
-  Expect.equals(0, p.load<int>());
+  Pointer<Uint8> p = allocate();
+  p.value = 255;
+  Expect.equals(255, p.value);
+  p.value = 0;
+  Expect.equals(0, p.value);
 
   Expect.equals(0x0000000000000000, 0);
   Expect.equals(0x0000000000000100, 256);
-  p.store(256);
-  Expect.equals(0, p.load<int>()); // truncated
+  p.value = 256;
+  Expect.equals(0, p.value); // truncated
 
   Expect.equals(0xFFFFFFFFFFFFFFFF, -1);
   Expect.equals(0x00000000000000FF, 255);
-  p.store(-1);
-  Expect.equals(255, p.load<int>()); // truncated
-  p.free();
+  p.value = -1;
+  Expect.equals(255, p.value); // truncated
+  free(p);
 }
 
 void testRangeInt16() {
-  ffi.Pointer<ffi.Int16> p = Pointer.allocate();
-  p.store(0x7FFF);
-  Expect.equals(0x7FFF, p.load<int>());
-  p.store(-0x8000);
-  Expect.equals(-0x8000, p.load<int>());
-  p.store(0x8000);
-  Expect.equals(
-      0xFFFFFFFFFFFF8000, p.load<int>()); // truncated and sign extended
-  p.store(-0x8001);
-  Expect.equals(0x7FFF, p.load<int>()); // truncated
-  p.free();
+  Pointer<Int16> p = allocate();
+  p.value = 0x7FFF;
+  Expect.equals(0x7FFF, p.value);
+  p.value = -0x8000;
+  Expect.equals(-0x8000, p.value);
+  p.value = 0x8000;
+  Expect.equals(0xFFFFFFFFFFFF8000, p.value); // truncated and sign extended
+  p.value = -0x8001;
+  Expect.equals(0x7FFF, p.value); // truncated
+  free(p);
 }
 
 void testRangeUint16() {
-  ffi.Pointer<ffi.Uint16> p = Pointer.allocate();
-  p.store(0xFFFF);
-  Expect.equals(0xFFFF, p.load<int>());
-  p.store(0);
-  Expect.equals(0, p.load<int>());
-  p.store(0x10000);
-  Expect.equals(0, p.load<int>()); // truncated
-  p.store(-1);
-  Expect.equals(0xFFFF, p.load<int>()); // truncated
-  p.free();
+  Pointer<Uint16> p = allocate();
+  p.value = 0xFFFF;
+  Expect.equals(0xFFFF, p.value);
+  p.value = 0;
+  Expect.equals(0, p.value);
+  p.value = 0x10000;
+  Expect.equals(0, p.value); // truncated
+  p.value = -1;
+  Expect.equals(0xFFFF, p.value); // truncated
+  free(p);
 }
 
 void testRangeInt32() {
-  ffi.Pointer<ffi.Int32> p = Pointer.allocate();
-  p.store(0x7FFFFFFF);
-  Expect.equals(0x7FFFFFFF, p.load<int>());
-  p.store(-0x80000000);
-  Expect.equals(-0x80000000, p.load<int>());
-  p.store(0x80000000);
-  Expect.equals(
-      0xFFFFFFFF80000000, p.load<int>()); // truncated and sign extended
-  p.store(-0x80000001);
-  Expect.equals(0x7FFFFFFF, p.load<int>()); // truncated
-  p.free();
+  Pointer<Int32> p = allocate();
+  p.value = 0x7FFFFFFF;
+  Expect.equals(0x7FFFFFFF, p.value);
+  p.value = -0x80000000;
+  Expect.equals(-0x80000000, p.value);
+  p.value = 0x80000000;
+  Expect.equals(0xFFFFFFFF80000000, p.value); // truncated and sign extended
+  p.value = -0x80000001;
+  Expect.equals(0x7FFFFFFF, p.value); // truncated
+  free(p);
 }
 
 void testRangeUint32() {
-  ffi.Pointer<ffi.Uint32> p = Pointer.allocate();
-  p.store(0xFFFFFFFF);
-  Expect.equals(0xFFFFFFFF, p.load<int>());
-  p.store(0);
-  Expect.equals(0, p.load<int>());
-  p.store(0x100000000);
-  Expect.equals(0, p.load<int>()); // truncated
-  p.store(-1);
-  Expect.equals(0xFFFFFFFF, p.load<int>()); // truncated
-  p.free();
+  Pointer<Uint32> p = allocate();
+  p.value = 0xFFFFFFFF;
+  Expect.equals(0xFFFFFFFF, p.value);
+  p.value = 0;
+  Expect.equals(0, p.value);
+  p.value = 0x100000000;
+  Expect.equals(0, p.value); // truncated
+  p.value = -1;
+  Expect.equals(0xFFFFFFFF, p.value); // truncated
+  free(p);
 }
 
 void testRangeInt64() {
-  ffi.Pointer<ffi.Int64> p = Pointer.allocate();
-  p.store(0x7FFFFFFFFFFFFFFF); // 2 ^ 63 - 1
-  Expect.equals(0x7FFFFFFFFFFFFFFF, p.load<int>());
-  p.store(-0x8000000000000000); // -2 ^ 63
-  Expect.equals(-0x8000000000000000, p.load<int>());
-  p.free();
+  Pointer<Int64> p = allocate();
+  p.value = 0x7FFFFFFFFFFFFFFF; // 2 ^ 63 - 1
+  Expect.equals(0x7FFFFFFFFFFFFFFF, p.value);
+  p.value = -0x8000000000000000; // -2 ^ 63
+  Expect.equals(-0x8000000000000000, p.value);
+  free(p);
 }
 
 void testRangeUint64() {
-  ffi.Pointer<ffi.Uint64> p = Pointer.allocate();
-  p.store(0x7FFFFFFFFFFFFFFF); // 2 ^ 63 - 1
-  Expect.equals(0x7FFFFFFFFFFFFFFF, p.load<int>());
-  p.store(-0x8000000000000000); // -2 ^ 63 interpreted as 2 ^ 63
-  Expect.equals(-0x8000000000000000, p.load<int>());
+  Pointer<Uint64> p = allocate();
+  p.value = 0x7FFFFFFFFFFFFFFF; // 2 ^ 63 - 1
+  Expect.equals(0x7FFFFFFFFFFFFFFF, p.value);
+  p.value = -0x8000000000000000; // -2 ^ 63 interpreted as 2 ^ 63
+  Expect.equals(-0x8000000000000000, p.value);
 
   // Dart allows interpreting bits both signed and unsigned
   Expect.equals(0xFFFFFFFFFFFFFFFF, -1);
-  p.store(-1); // -1 interpreted as 2 ^ 64 - 1
-  Expect.equals(-1, p.load<int>());
-  Expect.equals(0xFFFFFFFFFFFFFFFF, p.load<int>());
-  p.free();
+  p.value = -1; // -1 interpreted as 2 ^ 64 - 1
+  Expect.equals(-1, p.value);
+  Expect.equals(0xFFFFFFFFFFFFFFFF, p.value);
+  free(p);
 }
 
 void testRangeIntPtr() {
-  ffi.Pointer<ffi.IntPtr> p = Pointer.allocate();
+  Pointer<IntPtr> p = allocate();
   int pAddr = p.address;
-  p.store(pAddr); // its own address should fit
-  p.store(0x7FFFFFFF); // and 32 bit addresses should fit
-  Expect.equals(0x7FFFFFFF, p.load<int>());
-  p.store(-0x80000000);
-  Expect.equals(-0x80000000, p.load<int>());
-  p.free();
+  p.value = pAddr; // its own address should fit
+  p.value = 0x7FFFFFFF; // and 32 bit addresses should fit
+  Expect.equals(0x7FFFFFFF, p.value);
+  p.value = -0x80000000;
+  Expect.equals(-0x80000000, p.value);
+  free(p);
 }
 
 void testFloat() {
-  ffi.Pointer<ffi.Float> p = Pointer.allocate();
-  p.store(1.511366173271439e-13);
-  Expect.equals(1.511366173271439e-13, p.load<double>());
-  p.store(1.4260258159703532e-105); // float does not have enough precision
-  Expect.notEquals(1.4260258159703532e-105, p.load<double>());
-  p.free();
+  Pointer<Float> p = allocate();
+  p.value = 1.511366173271439e-13;
+  Expect.equals(1.511366173271439e-13, p.value);
+  p.value = 1.4260258159703532e-105; // float does not have enough precision
+  Expect.notEquals(1.4260258159703532e-105, p.value);
+  free(p);
 }
 
 void testDouble() {
-  ffi.Pointer<ffi.Double> p = Pointer.allocate();
-  p.store(1.4260258159703532e-105);
-  Expect.equals(1.4260258159703532e-105, p.load<double>());
-  p.free();
+  Pointer<Double> p = allocate();
+  p.value = 1.4260258159703532e-105;
+  Expect.equals(1.4260258159703532e-105, p.value);
+  free(p);
 }
 
 void testVoid() {
-  ffi.Pointer<ffi.IntPtr> p1 = Pointer.allocate();
-  ffi.Pointer<ffi.Void> p2 = p1.cast(); // make this dart pointer opaque
+  Pointer<IntPtr> p1 = allocate();
+  Pointer<Void> p2 = p1.cast(); // make this dart pointer opaque
   p2.address; // we can print the address
-  p2.free();
+  free(p2);
 }
 
 void testPointerPointer() {
-  ffi.Pointer<ffi.Int16> p = Pointer.allocate();
-  p.store(17);
-  ffi.Pointer<ffi.Pointer<ffi.Int16>> p2 = Pointer.allocate();
-  p2.store(p);
-  Expect.equals(17, p2.load<ffi.Pointer<ffi.Int16>>().load<int>());
-  p2.free();
-  p.free();
+  Pointer<Int16> p = allocate();
+  p.value = 17;
+  Pointer<Pointer<Int16>> p2 = allocate();
+  p2.value = p;
+  Expect.equals(17, p2.value.value);
+  free(p2);
+  free(p);
 }
 
 void testPointerPointerNull() {
-  Pointer<Pointer<ffi.Int8>> pointerToPointer = Pointer.allocate();
-  Pointer<ffi.Int8> value = ffi.nullptr.cast();
-  pointerToPointer.store(value);
-  value = pointerToPointer.load();
-  Expect.equals(value, ffi.nullptr);
-  value = Pointer.allocate();
-  pointerToPointer.store(value);
-  value = pointerToPointer.load();
+  Pointer<Pointer<Int8>> pointerToPointer = allocate();
+  Pointer<Int8> value = nullptr;
+  pointerToPointer.value = value;
+  value = pointerToPointer.value;
+  Expect.equals(value, nullptr);
+  value = allocate();
+  pointerToPointer.value = value;
+  value = pointerToPointer.value;
   Expect.isNotNull(value);
-  value.free();
-  value = ffi.nullptr.cast();
-  pointerToPointer.store(value);
-  value = pointerToPointer.load();
-  Expect.equals(value, ffi.nullptr);
-  pointerToPointer.free();
+  free(value);
+  value = nullptr;
+  pointerToPointer.value = value;
+  value = pointerToPointer.value;
+  Expect.equals(value, nullptr);
+  free(pointerToPointer);
 }
 
 void testPointerStoreNull() {
   int i = null;
-  ffi.Pointer<ffi.Int8> p = Pointer.allocate();
-  Expect.throws(() => p.store(i));
-  p.free();
+  Pointer<Int8> p = allocate();
+  Expect.throws(() => p.value = i);
+  free(p);
   double d = null;
-  ffi.Pointer<ffi.Float> p2 = Pointer.allocate();
-  Expect.throws(() => p2.store(d));
-  p2.free();
-  Pointer<ffi.Void> x = null;
-  ffi.Pointer<ffi.Pointer<ffi.Void>> p3 = Pointer.allocate();
-  Expect.throws(() => p3.store(x));
-  p3.free();
+  Pointer<Float> p2 = allocate();
+  Expect.throws(() => p2.value = d);
+  free(p2);
+  Pointer<Void> x = null;
+  Pointer<Pointer<Void>> p3 = allocate();
+  Expect.throws(() => p3.value = x);
+  free(p3);
 }
 
 void testSizeOf() {
-  Expect.equals(1, ffi.sizeOf<ffi.Int8>());
-  Expect.equals(2, ffi.sizeOf<ffi.Int16>());
-  Expect.equals(4, ffi.sizeOf<ffi.Int32>());
-  Expect.equals(8, ffi.sizeOf<ffi.Int64>());
-  Expect.equals(1, ffi.sizeOf<ffi.Uint8>());
-  Expect.equals(2, ffi.sizeOf<ffi.Uint16>());
-  Expect.equals(4, ffi.sizeOf<ffi.Uint32>());
-  Expect.equals(8, ffi.sizeOf<ffi.Uint64>());
-  Expect.equals(
-      true, 4 == ffi.sizeOf<ffi.IntPtr>() || 8 == ffi.sizeOf<ffi.IntPtr>());
-  Expect.equals(4, ffi.sizeOf<ffi.Float>());
-  Expect.equals(8, ffi.sizeOf<ffi.Double>());
+  Expect.equals(1, sizeOf<Int8>());
+  Expect.equals(2, sizeOf<Int16>());
+  Expect.equals(4, sizeOf<Int32>());
+  Expect.equals(8, sizeOf<Int64>());
+  Expect.equals(1, sizeOf<Uint8>());
+  Expect.equals(2, sizeOf<Uint16>());
+  Expect.equals(4, sizeOf<Uint32>());
+  Expect.equals(8, sizeOf<Uint64>());
+  Expect.equals(true, 4 == sizeOf<IntPtr>() || 8 == sizeOf<IntPtr>());
+  Expect.equals(4, sizeOf<Float>());
+  Expect.equals(8, sizeOf<Double>());
 }
 
 // note: stack overflows at around 15k calls
 void testPointerChain(int length) {
-  void createChain(ffi.Pointer<ffi.IntPtr> head, int length, int value) {
+  void createChain(Pointer<IntPtr> head, int length, int value) {
     if (length == 0) {
-      head.store(value);
+      head.value = value;
       return;
     }
-    ffi.Pointer<ffi.IntPtr> next = Pointer.allocate();
-    head.store(next.address);
+    Pointer<IntPtr> next = allocate();
+    head.value = next.address;
     createChain(next, length - 1, value);
   }
 
-  int getChainValue(ffi.Pointer<ffi.IntPtr> head, int length) {
+  int getChainValue(Pointer<IntPtr> head, int length) {
     if (length == 0) {
-      return head.load();
+      return head.value;
     }
-    ffi.Pointer<ffi.IntPtr> next = Pointer.fromAddress(head.load());
+    Pointer<IntPtr> next = Pointer.fromAddress(head.value);
     return getChainValue(next, length - 1);
   }
 
-  void freeChain(ffi.Pointer<ffi.IntPtr> head, int length) {
-    ffi.Pointer<ffi.IntPtr> next = Pointer.fromAddress(head.load());
-    head.free();
+  void freeChain(Pointer<IntPtr> head, int length) {
+    Pointer<IntPtr> next = Pointer.fromAddress(head.value);
+    free(head);
     if (length == 0) {
       return;
     }
     freeChain(next, length - 1);
   }
 
-  ffi.Pointer<ffi.IntPtr> head = Pointer.allocate();
+  Pointer<IntPtr> head = allocate();
   createChain(head, length, 512);
   int tailValue = getChainValue(head, length);
   Expect.equals(512, tailValue);
@@ -410,101 +413,126 @@
 }
 
 void testTypeTest() {
-  ffi.Pointer<ffi.Int8> p = Pointer.allocate();
-  Expect.isTrue(p is ffi.Pointer);
-  p.free();
+  Pointer<Int8> p = allocate();
+  Expect.isTrue(p is Pointer);
+  free(p);
 }
 
 void testToString() {
-  ffi.Pointer<ffi.Int16> p = Pointer.allocate();
+  Pointer<Int16> p = allocate();
   Expect.stringEquals(
       "Pointer<Int16>: address=0x", p.toString().substring(0, 26));
-  p.free();
-  ffi.Pointer<ffi.Int64> p2 = Pointer.fromAddress(0x123abc);
+  free(p);
+  Pointer<Int64> p2 = Pointer.fromAddress(0x123abc);
   Expect.stringEquals("Pointer<Int64>: address=0x123abc", p2.toString());
 }
 
 void testEquality() {
-  ffi.Pointer<ffi.Int8> p = Pointer.fromAddress(12345678);
-  ffi.Pointer<ffi.Int8> p2 = Pointer.fromAddress(12345678);
+  Pointer<Int8> p = Pointer.fromAddress(12345678);
+  Pointer<Int8> p2 = Pointer.fromAddress(12345678);
   Expect.equals(p, p2);
   Expect.equals(p.hashCode, p2.hashCode);
-  ffi.Pointer<ffi.Int16> p3 = p.cast();
+  Pointer<Int16> p3 = p.cast();
   Expect.equals(p, p3);
   Expect.equals(p.hashCode, p3.hashCode);
   Expect.notEquals(p, null);
   Expect.notEquals(null, p);
-  ffi.Pointer<ffi.Int8> p4 = p.offsetBy(1337);
+  Pointer<Int8> p4 = p.offsetBy(1337);
   Expect.notEquals(p, p4);
 }
 
-typedef Int8UnOp = ffi.Int8 Function(ffi.Int8);
+typedef Int8UnOp = Int8 Function(Int8);
 
 void testAllocateGeneric() {
-  ffi.Pointer<T> generic<T extends ffi.NativeType>() {
-    ffi.Pointer<T> pointer;
-    pointer = Pointer.allocate();
+  Pointer<T> generic<T extends NativeType>() {
+    Pointer<T> pointer;
+    pointer = allocate();
     return pointer;
   }
 
-  ffi.Pointer p = generic<ffi.Int64>();
-  p.free();
+  Pointer p = generic<Int64>();
+  free(p);
 }
 
 void testAllocateVoid() {
   Expect.throws(() {
-    ffi.Pointer<ffi.Void> p = Pointer.allocate();
+    Pointer<Void> p = allocate();
   });
 }
 
 void testAllocateNativeFunction() {
   Expect.throws(() {
-    ffi.Pointer<ffi.NativeFunction<Int8UnOp>> p = Pointer.allocate();
+    Pointer<NativeFunction<Int8UnOp>> p = allocate();
   });
 }
 
 void testAllocateNativeType() {
   Expect.throws(() {
-    Pointer.allocate();
+    allocate();
   });
 }
 
 void testSizeOfGeneric() {
-  int generic<T extends ffi.Pointer>() {
+  int generic<T extends Pointer>() {
     int size;
-    size = ffi.sizeOf<T>();
+    size = sizeOf<T>();
     return size;
   }
 
-  int size = generic<ffi.Pointer<ffi.Int64>>();
+  int size = generic<Pointer<Int64>>();
   Expect.isTrue(size == 8 || size == 4);
 }
 
 void testSizeOfVoid() {
   Expect.throws(() {
-    ffi.sizeOf<ffi.Void>();
+    sizeOf<Void>();
   });
 }
 
 void testSizeOfNativeFunction() {
   Expect.throws(() {
-    ffi.sizeOf<ffi.NativeFunction<Int8UnOp>>();
+    sizeOf<NativeFunction<Int8UnOp>>();
   });
 }
 
 void testSizeOfNativeType() {
   Expect.throws(() {
-    ffi.sizeOf();
+    sizeOf();
   });
 }
 
-void testFreeZeroOut() {
-  // at least one of these pointers should have address != 0 on all platforms
-  ffi.Pointer<ffi.Int8> p1 = Pointer.allocate();
-  ffi.Pointer<ffi.Int8> p2 = Pointer.allocate();
-  Expect.notEquals(0, p1.address & p2.address);
-  p1.free();
-  p2.free();
-  Expect.equals(0, p1.address);
-  Expect.equals(0, p2.address);
+void testDynamicInvocation() {
+  dynamic p = allocate<Int8>();
+  Expect.throws(() {
+    final int i = p.value;
+  });
+  Expect.throws(() => p.value = 1);
+  p.elementAt(5); // Works, but is slow.
+  final int addr = p.address;
+  final Pointer<Int16> p2 = p.cast<Int16>();
+  free(p);
+}
+
+final nullableInt64ElementAt1 = ffiTestFunctions.lookupFunction<
+    Pointer<Int64> Function(Pointer<Int64>),
+    Pointer<Int64> Function(Pointer<Int64>)>("NullableInt64ElemAt1");
+
+void testNullptrCast() {
+  Pointer<Int64> ptr = nullptr;
+  ptr = nullableInt64ElementAt1(ptr);
+  Expect.equals(ptr, nullptr);
+}
+
+void testMemoryAddressTruncation() {
+  const int kIgnoreBytesPositive = 0x1122334400000000;
+  const int kIgnoreBytesNegative = 0xffddccbb00000000;
+  if (sizeOf<IntPtr>() == 4) {
+    final p1 = Pointer<Int8>.fromAddress(123);
+    final p2 = Pointer<Int8>.fromAddress(123 + kIgnoreBytesPositive);
+    final p3 = Pointer<Int8>.fromAddress(123 + kIgnoreBytesNegative);
+    Expect.equals(p1.address, p2.address);
+    Expect.equals(p1, p2);
+    Expect.equals(p1.address, p3.address);
+    Expect.equals(p1, p3);
+  }
 }
diff --git a/tests/ffi/enable_ffi_test.dart b/tests/ffi/enable_ffi_test.dart
index 167c25c..3cbd635 100644
--- a/tests/ffi/enable_ffi_test.dart
+++ b/tests/ffi/enable_ffi_test.dart
@@ -11,10 +11,11 @@
 // VMOptions=--enable-ffi=false
 
 import 'dart:ffi'; //# 01: compile-time error, runtime error
+import 'package:ffi/ffi.dart'; //# 01: compile-time error, runtime error
 
 void main() {
   Pointer<Int8> p = //# 01: compile-time error, runtime error
-      Pointer.allocate(); //# 01: compile-time error, runtime error
+      allocate(); //# 01: compile-time error, runtime error
   print(p.address); //# 01: compile-time error, runtime error
-  p.free(); //# 01: compile-time error, runtime error
+  free(p); //# 01: compile-time error, runtime error
 }
diff --git a/tests/ffi/extension_methods_test.dart b/tests/ffi/extension_methods_test.dart
new file mode 100644
index 0000000..2e411b8
--- /dev/null
+++ b/tests/ffi/extension_methods_test.dart
@@ -0,0 +1,108 @@
+// 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:ffi';
+
+import "package:expect/expect.dart";
+import "package:ffi/ffi.dart";
+
+main(List<String> arguments) {
+  for (int i = 0; i < 100; i++) {
+    testStoreLoad();
+    testNullReceivers();
+    testNullIndices();
+    testNullArguments();
+    testReifiedGeneric();
+  }
+}
+
+testStoreLoad() {
+  final p = allocate<Int8>(count: 2);
+  p.value = 10;
+  Expect.equals(10, p.value);
+  p[1] = 20;
+  Expect.equals(20, p[1]);
+  if (sizeOf<IntPtr>() == 4) {
+    // Test round tripping.
+    Expect.equals(20, p.elementAt(0x100000001).value);
+    Expect.equals(20, p[0x100000001]);
+  }
+
+  // Test negative index.
+  final pUseNegative = p.elementAt(1);
+  Expect.equals(10, pUseNegative[-1]);
+
+  final p1 = allocate<Double>(count: 2);
+  p1.value = 10.0;
+  Expect.approxEquals(10.0, p1.value);
+  p1[1] = 20.0;
+  Expect.approxEquals(20.0, p1[1]);
+  free(p1);
+
+  final p2 = allocate<Pointer<Int8>>(count: 2);
+  p2.value = p;
+  Expect.equals(p, p2.value);
+  p2[1] = p;
+  Expect.equals(p, p2[1]);
+  free(p2);
+  free(p);
+
+  final p3 = allocate<Foo>();
+  Foo foo = p3.ref;
+  foo.a = 1;
+  Expect.equals(1, foo.a);
+  free(p3);
+}
+
+/// With extension methods, the receiver position can be null.
+testNullReceivers() {
+  Pointer<Int8> p = allocate();
+
+  Pointer<Int8> p4 = null;
+  Expect.throws(() => Expect.equals(10, p4.value));
+  Expect.throws(() => p4.value = 10);
+
+  Pointer<Pointer<Int8>> p5 = null;
+  Expect.throws(() => Expect.equals(10, p5.value));
+  Expect.throws(() => p5.value = p);
+
+  Pointer<Foo> p6 = null;
+  Expect.throws(() => Expect.equals(10, p6.ref));
+
+  free(p);
+}
+
+testNullIndices() {
+  Pointer<Int8> p = allocate();
+
+  Expect.throws(() => Expect.equals(10, p[null]));
+  Expect.throws(() => p[null] = 10);
+
+  Pointer<Pointer<Int8>> p5 = p.cast();
+  Expect.throws(() => Expect.equals(10, p5[null]));
+  Expect.throws(() => p5[null] = p);
+
+  Pointer<Foo> p6 = p.cast();
+  Expect.throws(() => Expect.equals(10, p6[null]));
+
+  free(p);
+}
+
+testNullArguments() {
+  Pointer<Int8> p = allocate();
+  Expect.throws(() => p.value = null);
+  free(p);
+}
+
+testReifiedGeneric() {
+  final p = allocate<Pointer<Int8>>();
+  Pointer<Pointer<NativeType>> p2 = p;
+  Expect.isTrue(p2.value is Pointer<Int8>);
+  free(p);
+}
+
+class Foo extends Struct {
+  @Int8()
+  int a;
+}
diff --git a/tests/ffi/external_typed_data_test.dart b/tests/ffi/external_typed_data_test.dart
index 266d3fb..8d19f79 100644
--- a/tests/ffi/external_typed_data_test.dart
+++ b/tests/ffi/external_typed_data_test.dart
@@ -7,6 +7,7 @@
 import 'dart:typed_data';
 
 import 'package:expect/expect.dart';
+import "package:ffi/ffi.dart";
 
 main() {
   testInt8Load();
@@ -25,7 +26,6 @@
   testInt64Store();
   testUint64Load();
   testUint64Store();
-  testIntPtr();
   testFloatLoad();
   testFloatStore();
   testDoubleLoad();
@@ -41,174 +41,162 @@
 
 void testInt8Load() {
   // Load
-  Pointer<Int8> ptr = Pointer.allocate();
-  ptr.store(0xff);
-  Int8List list = ptr.asExternalTypedData();
+  Pointer<Int8> ptr = allocate();
+  ptr.value = 0xff;
+  Int8List list = ptr.asTypedList(1);
   Expect.equals(list[0], -1);
   Expect.equals(list.length, 1);
-  ptr.free();
+  free(ptr);
 }
 
 void testInt8Store() {
   // Store
-  Pointer<Int8> ptr = Pointer.allocate();
-  Int8List list = ptr.asExternalTypedData();
+  Pointer<Int8> ptr = allocate();
+  Int8List list = ptr.asTypedList(1);
   list[0] = 0xff;
   Expect.equals(list.length, 1);
-  Expect.equals(ptr.load<int>(), -1);
-  ptr.free();
+  Expect.equals(ptr.value, -1);
+  free(ptr);
 }
 
 void testUint8Load() {
   // Load
-  Pointer<Uint8> ptr = Pointer.allocate();
-  ptr.store(0xff);
-  Uint8List list = ptr.asExternalTypedData();
+  Pointer<Uint8> ptr = allocate();
+  ptr.value = 0xff;
+  Uint8List list = ptr.asTypedList(1);
   Expect.equals(list[0], 0xff);
   Expect.equals(list.length, 1);
-  ptr.free();
+  free(ptr);
 }
 
 void testUint8Store() {
   // Store
-  Pointer<Uint8> ptr = Pointer.allocate();
-  Uint8List list = ptr.asExternalTypedData();
+  Pointer<Uint8> ptr = allocate();
+  Uint8List list = ptr.asTypedList(1);
   list[0] = 0xff;
   Expect.equals(list.length, 1);
-  Expect.equals(ptr.load<int>(), 0xff);
-  ptr.free();
+  Expect.equals(ptr.value, 0xff);
+  free(ptr);
 }
 
 void testInt16Load() {
   // Load
-  Pointer<Int16> ptr = Pointer.allocate();
-  ptr.store(0xffff);
-  Int16List list = ptr.asExternalTypedData();
+  Pointer<Int16> ptr = allocate();
+  ptr.value = 0xffff;
+  Int16List list = ptr.asTypedList(1);
   Expect.equals(list[0], -1);
   Expect.equals(list.length, 1);
-  ptr.free();
+  free(ptr);
 }
 
 void testInt16Store() {
   // Store
-  Pointer<Int16> ptr = Pointer.allocate();
-  Int16List list = ptr.asExternalTypedData();
+  Pointer<Int16> ptr = allocate();
+  Int16List list = ptr.asTypedList(1);
   list[0] = 0xffff;
   Expect.equals(list.length, 1);
-  Expect.equals(ptr.load<int>(), -1);
-  ptr.free();
+  Expect.equals(ptr.value, -1);
+  free(ptr);
 }
 
 void testUint16Load() {
   // Load
-  Pointer<Uint16> ptr = Pointer.allocate();
-  ptr.store(0xffff);
-  Uint16List list = ptr.asExternalTypedData();
+  Pointer<Uint16> ptr = allocate();
+  ptr.value = 0xffff;
+  Uint16List list = ptr.asTypedList(1);
   Expect.equals(list[0], 0xffff);
   Expect.equals(list.length, 1);
-  ptr.free();
+  free(ptr);
 }
 
 void testUint16Store() {
   // Store
-  Pointer<Uint16> ptr = Pointer.allocate();
-  Uint16List list = ptr.asExternalTypedData();
+  Pointer<Uint16> ptr = allocate();
+  Uint16List list = ptr.asTypedList(1);
   list[0] = 0xffff;
   Expect.equals(list.length, 1);
-  Expect.equals(ptr.load<int>(), 0xffff);
-  ptr.free();
+  Expect.equals(ptr.value, 0xffff);
+  free(ptr);
 }
 
 void testInt32Load() {
   // Load
-  Pointer<Int32> ptr = Pointer.allocate();
-  ptr.store(0xffffffff);
-  Int32List list = ptr.asExternalTypedData();
+  Pointer<Int32> ptr = allocate();
+  ptr.value = 0xffffffff;
+  Int32List list = ptr.asTypedList(1);
   Expect.equals(list[0], -1);
   Expect.equals(list.length, 1);
-  ptr.free();
+  free(ptr);
 }
 
 void testInt32Store() {
   // Store
-  Pointer<Int32> ptr = Pointer.allocate();
-  Int32List list = ptr.asExternalTypedData();
+  Pointer<Int32> ptr = allocate();
+  Int32List list = ptr.asTypedList(1);
   list[0] = 0xffffffff;
   Expect.equals(list.length, 1);
-  Expect.equals(ptr.load<int>(), -1);
-  ptr.free();
+  Expect.equals(ptr.value, -1);
+  free(ptr);
 }
 
 void testUint32Load() {
   // Load
-  Pointer<Uint32> ptr = Pointer.allocate();
-  ptr.store(0xffffffff);
-  Uint32List list = ptr.asExternalTypedData();
+  Pointer<Uint32> ptr = allocate();
+  ptr.value = 0xffffffff;
+  Uint32List list = ptr.asTypedList(1);
   Expect.equals(list[0], 0xffffffff);
   Expect.equals(list.length, 1);
-  ptr.free();
+  free(ptr);
 }
 
 void testUint32Store() {
   // Store
-  Pointer<Uint32> ptr = Pointer.allocate();
-  Uint32List list = ptr.asExternalTypedData();
+  Pointer<Uint32> ptr = allocate();
+  Uint32List list = ptr.asTypedList(1);
   list[0] = 0xffffffff;
   Expect.equals(list.length, 1);
-  Expect.equals(ptr.load<int>(), 0xffffffff);
-  ptr.free();
+  Expect.equals(ptr.value, 0xffffffff);
+  free(ptr);
 }
 
 void testInt64Load() {
   // Load
-  Pointer<Int64> ptr = Pointer.allocate();
-  ptr.store(0xffffffffffffffff);
-  Int64List list = ptr.asExternalTypedData();
+  Pointer<Int64> ptr = allocate();
+  ptr.value = 0xffffffffffffffff;
+  Int64List list = ptr.asTypedList(1);
   Expect.equals(list[0], -1);
   Expect.equals(list.length, 1);
-  ptr.free();
+  free(ptr);
 }
 
 void testInt64Store() {
   // Store
-  Pointer<Int64> ptr = Pointer.allocate();
-  Int64List list = ptr.asExternalTypedData();
+  Pointer<Int64> ptr = allocate();
+  Int64List list = ptr.asTypedList(1);
   list[0] = 0xffffffffffffffff;
   Expect.equals(list.length, 1);
-  Expect.equals(ptr.load<int>(), -1);
-  ptr.free();
+  Expect.equals(ptr.value, -1);
+  free(ptr);
 }
 
 void testUint64Load() {
   // Load
-  Pointer<Uint64> ptr = Pointer.allocate();
-  ptr.store(0xffffffffffffffff);
-  Uint64List list = ptr.asExternalTypedData();
+  Pointer<Uint64> ptr = allocate();
+  ptr.value = 0xffffffffffffffff;
+  Uint64List list = ptr.asTypedList(1);
   Expect.equals(list[0], 0xffffffffffffffff);
   Expect.equals(list.length, 1);
-  ptr.free();
+  free(ptr);
 }
 
 void testUint64Store() {
   // Store
-  Pointer<Uint64> ptr = Pointer.allocate();
-  Uint64List list = ptr.asExternalTypedData();
+  Pointer<Uint64> ptr = allocate();
+  Uint64List list = ptr.asTypedList(1);
   list[0] = 0xffffffffffffffff;
   Expect.equals(list.length, 1);
-  Expect.equals(ptr.load<int>(), 0xffffffffffffffff);
-  ptr.free();
-}
-
-void testIntPtr() {
-  bool is32Bit = sizeOf<IntPtr>() == 4;
-  Pointer<IntPtr> ptr = Pointer.allocate();
-  final array = ptr.asExternalTypedData();
-  if (is32Bit) {
-    Expect.type<Int32List>(array);
-  } else {
-    Expect.type<Int64List>(array);
-  }
-  ptr.free();
+  Expect.equals(ptr.value, 0xffffffffffffffff);
+  free(ptr);
 }
 
 double maxFloat = (2 - pow(2, -23)) * pow(2, 127);
@@ -216,92 +204,92 @@
 
 void testFloatLoad() {
   // Load
-  Pointer<Float> ptr = Pointer.allocate();
-  ptr.store(maxFloat);
-  Float32List list = ptr.asExternalTypedData();
+  Pointer<Float> ptr = allocate();
+  ptr.value = maxFloat;
+  Float32List list = ptr.asTypedList(1);
   Expect.equals(list[0], maxFloat);
   Expect.equals(list.length, 1);
-  ptr.free();
+  free(ptr);
 }
 
 void testFloatStore() {
   // Store
-  Pointer<Float> ptr = Pointer.allocate();
-  Float32List list = ptr.asExternalTypedData();
+  Pointer<Float> ptr = allocate();
+  Float32List list = ptr.asTypedList(1);
   list[0] = maxFloat;
   Expect.equals(list.length, 1);
-  Expect.equals(ptr.load<double>(), maxFloat);
-  ptr.free();
+  Expect.equals(ptr.value, maxFloat);
+  free(ptr);
 }
 
 void testDoubleLoad() {
   // Load
-  Pointer<Double> ptr = Pointer.allocate();
-  ptr.store(maxDouble);
-  Float64List list = ptr.asExternalTypedData();
+  Pointer<Double> ptr = allocate();
+  ptr.value = maxDouble;
+  Float64List list = ptr.asTypedList(1);
   Expect.equals(list[0], maxDouble);
   Expect.equals(list.length, 1);
-  ptr.free();
+  free(ptr);
 }
 
 void testDoubleStore() {
   // Store
-  Pointer<Double> ptr = Pointer.allocate();
-  Float64List list = ptr.asExternalTypedData();
+  Pointer<Double> ptr = allocate();
+  Float64List list = ptr.asTypedList(1);
   list[0] = maxDouble;
   Expect.equals(list.length, 1);
-  Expect.equals(ptr.load<double>(), maxDouble);
-  ptr.free();
+  Expect.equals(ptr.value, maxDouble);
+  free(ptr);
 }
 
 void testArrayLoad() {
   const int count = 0x100;
-  Pointer<Int32> ptr = Pointer.allocate(count: count);
+  Pointer<Int32> ptr = allocate(count: count);
   for (int i = 0; i < count; ++i) {
-    ptr.elementAt(i).store(i);
+    ptr[i] = i;
   }
-  Int32List array = ptr.asExternalTypedData(count: count);
+  Int32List array = ptr.asTypedList(count);
   for (int i = 0; i < count; ++i) {
     Expect.equals(array[i], i);
   }
-  ptr.free();
+  free(ptr);
 }
 
 void testArrayStore() {
   const int count = 0x100;
-  Pointer<Int32> ptr = Pointer.allocate(count: count);
-  Int32List array = ptr.asExternalTypedData(count: count);
+  Pointer<Int32> ptr = allocate(count: count);
+  Int32List array = ptr.asTypedList(count);
   for (int i = 0; i < count; ++i) {
     array[i] = i;
   }
   for (int i = 0; i < count; ++i) {
-    Expect.equals(ptr.elementAt(i).load<int>(), i);
+    Expect.equals(ptr[i], i);
   }
-  ptr.free();
+  free(ptr);
 }
 
 void testNegativeArray() {
-  Pointer<Int32> ptr = nullptr.cast();
-  Expect.throws<ArgumentError>(() => ptr.asExternalTypedData(count: -1));
+  Pointer<Int32> ptr = nullptr;
+  Expect.throws<ArgumentError>(() => ptr.asTypedList(-1));
 }
 
 // Tests that the address we're creating an ExternalTypedData from is aligned to
 // the element size.
 void testAlignment() {
   Expect.throws<ArgumentError>(
-      () => Pointer<Int16>.fromAddress(1).asExternalTypedData());
+      () => Pointer<Int16>.fromAddress(1).asTypedList(1));
   Expect.throws<ArgumentError>(
-      () => Pointer<Int32>.fromAddress(2).asExternalTypedData());
+      () => Pointer<Int32>.fromAddress(2).asTypedList(1));
   Expect.throws<ArgumentError>(
-      () => Pointer<Int64>.fromAddress(4).asExternalTypedData());
+      () => Pointer<Int64>.fromAddress(4).asTypedList(1));
   Expect.throws<ArgumentError>(
-      () => Pointer<Uint16>.fromAddress(1).asExternalTypedData());
+      () => Pointer<Uint16>.fromAddress(1).asTypedList(1));
   Expect.throws<ArgumentError>(
-      () => Pointer<Uint32>.fromAddress(2).asExternalTypedData());
+      () => Pointer<Uint32>.fromAddress(2).asTypedList(1));
   Expect.throws<ArgumentError>(
-      () => Pointer<Uint64>.fromAddress(4).asExternalTypedData());
+      () => Pointer<Uint64>.fromAddress(4).asTypedList(1));
   Expect.throws<ArgumentError>(
-      () => Pointer<Float>.fromAddress(2).asExternalTypedData());
+      () => Pointer<Float>.fromAddress(2).asTypedList(1));
   Expect.throws<ArgumentError>(
-      () => Pointer<Double>.fromAddress(4).asExternalTypedData());
+      () => Pointer<Double>.fromAddress(4).asTypedList(1));
 }
diff --git a/tests/ffi/ffi.status b/tests/ffi/ffi.status
index f2f9579..9f28066 100644
--- a/tests/ffi/ffi.status
+++ b/tests/ffi/ffi.status
@@ -19,7 +19,10 @@
 [ $arch == arm && $system != android ]
 *: Skip # "hardfp" calling convention is not yet supported (iOS is also supported but not tested): dartbug.com/36309
 
-[ $runtime != dart_precompiled && $runtime != vm ]
+[ $compiler == dart2analyzer ]
+enable_ffi_test: SkipByDesign # This is a check for VM only.
+
+[ $runtime != dart_precompiled && $runtime != vm && $compiler != dart2analyzer ]
 *: SkipByDesign # FFI is a VM-only feature. (This test suite is part of the default set.)
 
 [ $system != android && $system != linux && $system != macos && $system != windows ]
diff --git a/tests/ffi/ffi_test_helpers.dart b/tests/ffi/ffi_test_helpers.dart
index 84d3185..0c598ec 100644
--- a/tests/ffi/ffi_test_helpers.dart
+++ b/tests/ffi/ffi_test_helpers.dart
@@ -4,17 +4,17 @@
 //
 // Helpers for tests which trigger GC in delicate places.
 
-import 'dart:ffi' as ffi;
+import 'dart:ffi';
 
 import 'dylib_utils.dart';
 
-typedef NativeNullaryOp = ffi.Void Function();
+typedef NativeNullaryOp = Void Function();
 typedef NullaryOpVoid = void Function();
 
-typedef NativeUnaryOp = ffi.Void Function(ffi.IntPtr);
+typedef NativeUnaryOp = Void Function(IntPtr);
 typedef UnaryOpVoid = void Function(int);
 
-final ffi.DynamicLibrary ffiTestFunctions =
+final DynamicLibrary ffiTestFunctions =
     dlopenPlatformSpecific("ffi_test_functions");
 
 final triggerGc = ffiTestFunctions
@@ -22,3 +22,7 @@
 
 final collectOnNthAllocation = ffiTestFunctions
     .lookupFunction<NativeUnaryOp, UnaryOpVoid>("CollectOnNthAllocation");
+
+extension PointerOffsetBy<T extends NativeType> on Pointer<T> {
+  Pointer<T> offsetBy(int bytes) => Pointer.fromAddress(address + bytes);
+}
diff --git a/tests/ffi/function_callbacks_test.dart b/tests/ffi/function_callbacks_test.dart
index ca2197f..77f6def 100644
--- a/tests/ffi/function_callbacks_test.dart
+++ b/tests/ffi/function_callbacks_test.dart
@@ -143,7 +143,7 @@
 }
 
 typedef StoreType = Pointer<Int64> Function(Pointer<Int64>);
-Pointer<Int64> store(Pointer<Int64> ptr) => ptr.elementAt(1)..store(1337);
+Pointer<Int64> store(Pointer<Int64> ptr) => ptr.elementAt(1)..value = 1337;
 
 typedef NullPointersType = Pointer<Int64> Function(Pointer<Int64>);
 Pointer<Int64> nullPointers(Pointer<Int64> ptr) => ptr.elementAt(1);
@@ -179,18 +179,24 @@
   triggerGc();
 }
 
-typedef WaitForHelper = Void Function(Pointer<Void>);
+typedef WaitForHelperNative = Void Function(Pointer<Void>);
+typedef WaitForHelper = void Function(Pointer<Void>);
+
 void waitForHelper(Pointer<Void> helper) {
   print("helper: $helper");
-  testLibrary.lookupFunction<WaitForHelper, WaitForHelper>("WaitForHelper")(helper);
+  testLibrary
+      .lookupFunction<WaitForHelperNative, WaitForHelper>("WaitForHelper")(helper);
 }
 
 final List<Test> testcases = [
-  Test("SimpleAddition", Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 0)),
-  Test("IntComputation", Pointer.fromFunction<IntComputationType>(intComputation, 0)),
-  Test(
-      "UintComputation", Pointer.fromFunction<UintComputationType>(uintComputation, 0)),
-  Test("SimpleMultiply", Pointer.fromFunction<SimpleMultiplyType>(simpleMultiply, 0.0)),
+  Test("SimpleAddition",
+      Pointer.fromFunction<SimpleAdditionType>(simpleAddition, 0)),
+  Test("IntComputation",
+      Pointer.fromFunction<IntComputationType>(intComputation, 0)),
+  Test("UintComputation",
+      Pointer.fromFunction<UintComputationType>(uintComputation, 0)),
+  Test("SimpleMultiply",
+      Pointer.fromFunction<SimpleMultiplyType>(simpleMultiply, 0.0)),
   Test("SimpleMultiplyFloat",
       Pointer.fromFunction<SimpleMultiplyFloatType>(simpleMultiplyFloat, 0.0)),
   Test("ManyInts", Pointer.fromFunction<ManyIntsType>(manyInts, 0)),
@@ -202,17 +208,17 @@
   Test("ReturnVoid", Pointer.fromFunction<ReturnVoid>(returnVoid)),
   Test("ThrowExceptionDouble",
       Pointer.fromFunction<ThrowExceptionDouble>(throwExceptionDouble, 42.0)),
-  Test(
-      "ThrowExceptionPointer",
-      Pointer.fromFunction<ThrowExceptionPointer>(
-          throwExceptionPointer)),
-  Test("ThrowException", Pointer.fromFunction<ThrowExceptionInt>(throwExceptionInt, 42)),
+  Test("ThrowExceptionPointer",
+      Pointer.fromFunction<ThrowExceptionPointer>(throwExceptionPointer)),
+  Test("ThrowException",
+      Pointer.fromFunction<ThrowExceptionInt>(throwExceptionInt, 42)),
   Test("GC", Pointer.fromFunction<ReturnVoid>(testGC)),
-  Test("UnprotectCode", Pointer.fromFunction<WaitForHelper>(waitForHelper)),
+  Test("UnprotectCode", Pointer.fromFunction<WaitForHelperNative>(waitForHelper)),
 ];
 
 testCallbackWrongThread() =>
-    Test("CallbackWrongThread", Pointer.fromFunction<ReturnVoid>(returnVoid)).run();
+    Test("CallbackWrongThread", Pointer.fromFunction<ReturnVoid>(returnVoid))
+        .run();
 
 testCallbackOutsideIsolate() =>
     Test("CallbackOutsideIsolate", Pointer.fromFunction<ReturnVoid>(returnVoid))
@@ -227,7 +233,8 @@
 }
 
 testCallbackWrongIsolate() async {
-  final int callbackPointer = Pointer.fromFunction<ReturnVoid>(returnVoid).address;
+  final int callbackPointer =
+      Pointer.fromFunction<ReturnVoid>(returnVoid).address;
   final ReceivePort exitPort = ReceivePort();
   await Isolate.spawn(isolateHelper, callbackPointer,
       errorsAreFatal: true, onExit: exitPort.sendPort);
@@ -246,6 +253,8 @@
   Pointer.fromFunction<Double Function()>(testExceptionalReturn, "abc");  //# 61: compile-time error
   Pointer.fromFunction<Double Function()>(testExceptionalReturn, 0);  //# 62: compile-time error
   Pointer.fromFunction<Double Function()>(testExceptionalReturn);  //# 63: compile-time error
+
+  return 0.0;  // not used
 }
 
 void main() async {
@@ -262,7 +271,7 @@
     await testCallbackWrongIsolate(); //# 03: ok
   }
 
-  testManyCallbacks();  //# 04: ok
+  testManyCallbacks(); //# 04: ok
 }
 
 void testManyCallbacks() {
diff --git a/tests/ffi/function_gc_test.dart b/tests/ffi/function_gc_test.dart
index ed56e34..eea09d5 100644
--- a/tests/ffi/function_gc_test.dart
+++ b/tests/ffi/function_gc_test.dart
@@ -18,7 +18,6 @@
 // SharedObjects=ffi_test_functions
 
 import 'dart:ffi' as ffi;
-import 'dylib_utils.dart';
 import "package:expect/expect.dart";
 import 'ffi_test_helpers.dart';
 
diff --git a/tests/ffi/function_structs_test.dart b/tests/ffi/function_structs_test.dart
index bf41a08..ee71a4b 100644
--- a/tests/ffi/function_structs_test.dart
+++ b/tests/ffi/function_structs_test.dart
@@ -9,12 +9,12 @@
 
 library FfiTest;
 
-import 'dart:ffi' as ffi;
-import 'dart:ffi' show Pointer;
+import 'dart:ffi';
 
 import 'dylib_utils.dart';
 
 import "package:expect/expect.dart";
+import "package:ffi/ffi.dart";
 
 import 'coordinate.dart';
 import 'very_large_struct.dart';
@@ -23,45 +23,43 @@
 
 void main() {
   testFunctionWithStruct();
-  testFunctionWithStructArray();
-  testFunctionWithVeryLargeStruct();
+  // testFunctionWithStructArray();
+  // testFunctionWithVeryLargeStruct();
 }
 
-ffi.DynamicLibrary ffiTestFunctions =
-    dlopenPlatformSpecific("ffi_test_functions");
+DynamicLibrary ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
 
 /// pass a struct to a c function and get a struct as return value
 void testFunctionWithStruct() {
-  ffi.Pointer<ffi.NativeFunction<NativeCoordinateOp>> p1 =
+  Pointer<NativeFunction<NativeCoordinateOp>> p1 =
       ffiTestFunctions.lookup("TransposeCoordinate");
   NativeCoordinateOp f1 = p1.asFunction();
 
-  Pointer<Coordinate> c1 =
-      Coordinate.allocate(10.0, 20.0, ffi.nullptr.cast<Coordinate>()).addressOf;
+  Pointer<Coordinate> c1 = Coordinate.allocate(10.0, 20.0, nullptr).addressOf;
   Pointer<Coordinate> c2 = Coordinate.allocate(42.0, 84.0, c1).addressOf;
-  c1.load<Coordinate>().next = c2;
+  c1.ref.next = c2;
 
-  Coordinate result = f1(c1).load();
+  Coordinate result = f1(c1).ref;
 
-  Expect.approxEquals(20.0, c1.load<Coordinate>().x);
-  Expect.approxEquals(30.0, c1.load<Coordinate>().y);
+  Expect.approxEquals(20.0, c1.ref.x);
+  Expect.approxEquals(30.0, c1.ref.y);
 
   Expect.approxEquals(42.0, result.x);
   Expect.approxEquals(84.0, result.y);
 
-  c1.free();
-  c2.free();
+  free(c1);
+  free(c2);
 }
 
 /// pass an array of structs to a c funtion
 void testFunctionWithStructArray() {
-  ffi.Pointer<ffi.NativeFunction<NativeCoordinateOp>> p1 =
+  Pointer<NativeFunction<NativeCoordinateOp>> p1 =
       ffiTestFunctions.lookup("CoordinateElemAt1");
   NativeCoordinateOp f1 = p1.asFunction();
 
-  Coordinate c1 = Pointer<Coordinate>.allocate(count: 3).load();
-  Coordinate c2 = c1.addressOf.elementAt(1).load();
-  Coordinate c3 = c1.addressOf.elementAt(2).load();
+  Coordinate c1 = allocate<Coordinate>(count: 3).ref;
+  Coordinate c2 = c1.addressOf[1];
+  Coordinate c3 = c1.addressOf[2];
   c1.x = 10.0;
   c1.y = 10.0;
   c1.next = c3.addressOf;
@@ -72,23 +70,23 @@
   c3.y = 30.0;
   c3.next = c2.addressOf;
 
-  Coordinate result = f1(c1.addressOf).load();
+  Coordinate result = f1(c1.addressOf).ref;
   Expect.approxEquals(20.0, result.x);
   Expect.approxEquals(20.0, result.y);
 
-  c1.addressOf.free();
+  free(c1.addressOf);
 }
 
 typedef VeryLargeStructSum = int Function(Pointer<VeryLargeStruct>);
-typedef NativeVeryLargeStructSum = ffi.Int64 Function(Pointer<VeryLargeStruct>);
+typedef NativeVeryLargeStructSum = Int64 Function(Pointer<VeryLargeStruct>);
 
 void testFunctionWithVeryLargeStruct() {
-  ffi.Pointer<ffi.NativeFunction<NativeVeryLargeStructSum>> p1 =
+  Pointer<NativeFunction<NativeVeryLargeStructSum>> p1 =
       ffiTestFunctions.lookup("SumVeryLargeStruct");
   VeryLargeStructSum f = p1.asFunction();
 
-  VeryLargeStruct vls1 = Pointer<VeryLargeStruct>.allocate(count: 2).load();
-  VeryLargeStruct vls2 = vls1.addressOf.elementAt(1).load();
+  VeryLargeStruct vls1 = allocate<VeryLargeStruct>(count: 2).ref;
+  VeryLargeStruct vls2 = vls1.addressOf[1];
   List<VeryLargeStruct> structs = [vls1, vls2];
   for (VeryLargeStruct struct in structs) {
     struct.a = 1;
@@ -108,9 +106,9 @@
   vls1.numChildren = 2;
   vls1.children = vls1.addressOf;
   vls2.parent = vls2.addressOf;
-  vls2.parent = ffi.nullptr.cast();
+  vls2.parent = nullptr;
   vls2.numChildren = 0;
-  vls2.children = ffi.nullptr.cast();
+  vls2.children = nullptr;
 
   int result = f(vls1.addressOf);
   Expect.equals(2051, result);
@@ -118,5 +116,5 @@
   result = f(vls2.addressOf);
   Expect.equals(2048, result);
 
-  vls1.addressOf.free();
+  free(vls1.addressOf);
 }
diff --git a/tests/ffi/function_test.dart b/tests/ffi/function_test.dart
index b4e6d7c..51cc2fe 100644
--- a/tests/ffi/function_test.dart
+++ b/tests/ffi/function_test.dart
@@ -15,11 +15,11 @@
 
 library FfiTest;
 
-import 'dart:ffi' as ffi;
-import 'dart:ffi' show Pointer;
+import 'dart:ffi';
 
 import 'dylib_utils.dart';
 
+import "package:ffi/ffi.dart";
 import "package:expect/expect.dart";
 
 void main() {
@@ -47,27 +47,24 @@
   }
 }
 
-ffi.DynamicLibrary ffiTestFunctions =
-    dlopenPlatformSpecific("ffi_test_functions");
+DynamicLibrary ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
 
-typedef NativeBinaryOp = ffi.Int32 Function(ffi.Int32, ffi.Int32);
+typedef NativeBinaryOp = Int32 Function(Int32, Int32);
 typedef UnaryOp = int Function(int);
 typedef BinaryOp = int Function(int, int);
 typedef GenericBinaryOp<T> = int Function(int, T);
 
 void testNativeFunctionFromCast() {
-  ffi.Pointer<ffi.IntPtr> p1 = Pointer.allocate();
-  ffi.Pointer<ffi.NativeFunction<NativeBinaryOp>> p2 = p1.cast();
+  Pointer<IntPtr> p1 = allocate();
+  Pointer<NativeFunction<NativeBinaryOp>> p2 = p1.cast();
   p2.asFunction<BinaryOp>();
   p2.asFunction<GenericBinaryOp<int>>();
-  p1.free();
+  free(p1);
 }
 
-typedef NativeQuadOpSigned = ffi.Int64 Function(
-    ffi.Int8, ffi.Int16, ffi.Int32, ffi.Int64);
+typedef NativeQuadOpSigned = Int64 Function(Int8, Int16, Int32, Int64);
 typedef QuadOp = int Function(int, int, int, int);
-typedef NativeQuadOpUnsigned = ffi.Uint64 Function(
-    ffi.Uint8, ffi.Uint16, ffi.Uint32, ffi.Uint64);
+typedef NativeQuadOpUnsigned = Uint64 Function(Uint8, Uint16, Uint32, Uint64);
 
 BinaryOp sumPlus42 =
     ffiTestFunctions.lookupFunction<NativeBinaryOp, BinaryOp>("SumPlus42");
@@ -86,76 +83,76 @@
       -0x8000000000000000, intComputation(0, 0, 0, -0x8000000000000000));
 }
 
-typedef NativeReturnMaxUint8 = ffi.Uint8 Function();
+typedef NativeReturnMaxUint8 = Uint8 Function();
 int Function() returnMaxUint8 = ffiTestFunctions
     .lookup("ReturnMaxUint8")
-    .cast<ffi.NativeFunction<NativeReturnMaxUint8>>()
+    .cast<NativeFunction<NativeReturnMaxUint8>>()
     .asFunction();
 
-typedef NativeReturnMaxUint16 = ffi.Uint16 Function();
+typedef NativeReturnMaxUint16 = Uint16 Function();
 int Function() returnMaxUint16 = ffiTestFunctions
     .lookup("ReturnMaxUint16")
-    .cast<ffi.NativeFunction<NativeReturnMaxUint16>>()
+    .cast<NativeFunction<NativeReturnMaxUint16>>()
     .asFunction();
 
-typedef NativeReturnMaxUint32 = ffi.Uint32 Function();
+typedef NativeReturnMaxUint32 = Uint32 Function();
 int Function() returnMaxUint32 = ffiTestFunctions
     .lookup("ReturnMaxUint32")
-    .cast<ffi.NativeFunction<NativeReturnMaxUint32>>()
+    .cast<NativeFunction<NativeReturnMaxUint32>>()
     .asFunction();
 
-typedef NativeReturnMinInt8 = ffi.Int8 Function();
+typedef NativeReturnMinInt8 = Int8 Function();
 int Function() returnMinInt8 = ffiTestFunctions
     .lookup("ReturnMinInt8")
-    .cast<ffi.NativeFunction<NativeReturnMinInt8>>()
+    .cast<NativeFunction<NativeReturnMinInt8>>()
     .asFunction();
 
-typedef NativeReturnMinInt16 = ffi.Int16 Function();
+typedef NativeReturnMinInt16 = Int16 Function();
 int Function() returnMinInt16 = ffiTestFunctions
     .lookup("ReturnMinInt16")
-    .cast<ffi.NativeFunction<NativeReturnMinInt16>>()
+    .cast<NativeFunction<NativeReturnMinInt16>>()
     .asFunction();
 
-typedef NativeReturnMinInt32 = ffi.Int32 Function();
+typedef NativeReturnMinInt32 = Int32 Function();
 int Function() returnMinInt32 = ffiTestFunctions
     .lookup("ReturnMinInt32")
-    .cast<ffi.NativeFunction<NativeReturnMinInt32>>()
+    .cast<NativeFunction<NativeReturnMinInt32>>()
     .asFunction();
 
-typedef NativeTakeMaxUint8 = ffi.IntPtr Function(ffi.Uint8);
+typedef NativeTakeMaxUint8 = IntPtr Function(Uint8);
 int Function(int) takeMaxUint8 = ffiTestFunctions
     .lookup("TakeMaxUint8")
-    .cast<ffi.NativeFunction<NativeTakeMaxUint8>>()
+    .cast<NativeFunction<NativeTakeMaxUint8>>()
     .asFunction();
 
-typedef NativeTakeMaxUint16 = ffi.IntPtr Function(ffi.Uint16);
+typedef NativeTakeMaxUint16 = IntPtr Function(Uint16);
 int Function(int) takeMaxUint16 = ffiTestFunctions
     .lookup("TakeMaxUint16")
-    .cast<ffi.NativeFunction<NativeTakeMaxUint16>>()
+    .cast<NativeFunction<NativeTakeMaxUint16>>()
     .asFunction();
 
-typedef NativeTakeMaxUint32 = ffi.IntPtr Function(ffi.Uint32);
+typedef NativeTakeMaxUint32 = IntPtr Function(Uint32);
 int Function(int) takeMaxUint32 = ffiTestFunctions
     .lookup("TakeMaxUint32")
-    .cast<ffi.NativeFunction<NativeTakeMaxUint32>>()
+    .cast<NativeFunction<NativeTakeMaxUint32>>()
     .asFunction();
 
-typedef NativeTakeMinInt8 = ffi.IntPtr Function(ffi.Int8);
+typedef NativeTakeMinInt8 = IntPtr Function(Int8);
 int Function(int) takeMinInt8 = ffiTestFunctions
     .lookup("TakeMinInt8")
-    .cast<ffi.NativeFunction<NativeTakeMinInt8>>()
+    .cast<NativeFunction<NativeTakeMinInt8>>()
     .asFunction();
 
-typedef NativeTakeMinInt16 = ffi.IntPtr Function(ffi.Int16);
+typedef NativeTakeMinInt16 = IntPtr Function(Int16);
 int Function(int) takeMinInt16 = ffiTestFunctions
     .lookup("TakeMinInt16")
-    .cast<ffi.NativeFunction<NativeTakeMinInt16>>()
+    .cast<NativeFunction<NativeTakeMinInt16>>()
     .asFunction();
 
-typedef NativeTakeMinInt32 = ffi.IntPtr Function(ffi.Int32);
+typedef NativeTakeMinInt32 = IntPtr Function(Int32);
 int Function(int) takeMinInt32 = ffiTestFunctions
     .lookup("TakeMinInt32")
-    .cast<ffi.NativeFunction<NativeTakeMinInt32>>()
+    .cast<NativeFunction<NativeTakeMinInt32>>()
     .asFunction();
 
 void testExtension() {
@@ -188,8 +185,8 @@
   Expect.equals(-1, uintComputation(0, 0, 0, -1));
 }
 
-typedef NativeSenaryOp = ffi.Int64 Function(
-    ffi.Int8, ffi.Int16, ffi.Int32, ffi.Uint8, ffi.Uint16, ffi.Uint32);
+typedef NativeSenaryOp = Int64 Function(
+    Int8, Int16, Int32, Uint8, Uint16, Uint32);
 typedef SenaryOp = int Function(int, int, int, int, int, int);
 
 SenaryOp sumSmallNumbers = ffiTestFunctions
@@ -213,7 +210,7 @@
   Expect.equals(0xFFFFFFFF, sumSmallNumbers(0, 0, 0, 0, 0, -1));
 }
 
-typedef NativeDoubleUnaryOp = ffi.Double Function(ffi.Double);
+typedef NativeDoubleUnaryOp = Double Function(Double);
 typedef DoubleUnaryOp = double Function(double);
 
 DoubleUnaryOp times1_337Double = ffiTestFunctions
@@ -223,7 +220,7 @@
   Expect.approxEquals(2.0 * 1.337, times1_337Double(2.0));
 }
 
-typedef NativeFloatUnaryOp = ffi.Float Function(ffi.Float);
+typedef NativeFloatUnaryOp = Float Function(Float);
 
 DoubleUnaryOp times1_337Float = ffiTestFunctions
     .lookupFunction<NativeFloatUnaryOp, DoubleUnaryOp>("Times1_337Float");
@@ -232,17 +229,8 @@
   Expect.approxEquals(1337.0, times1_337Float(1000.0));
 }
 
-typedef NativeDecenaryOp = ffi.IntPtr Function(
-    ffi.IntPtr,
-    ffi.IntPtr,
-    ffi.IntPtr,
-    ffi.IntPtr,
-    ffi.IntPtr,
-    ffi.IntPtr,
-    ffi.IntPtr,
-    ffi.IntPtr,
-    ffi.IntPtr,
-    ffi.IntPtr);
+typedef NativeDecenaryOp = IntPtr Function(IntPtr, IntPtr, IntPtr, IntPtr,
+    IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr);
 typedef DecenaryOp = int Function(
     int, int, int, int, int, int, int, int, int, int);
 
@@ -253,18 +241,8 @@
   Expect.equals(55, sumManyInts(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
 }
 
-typedef NativeUndenaryOp = ffi.IntPtr Function(
-    ffi.IntPtr,
-    ffi.IntPtr,
-    ffi.IntPtr,
-    ffi.IntPtr,
-    ffi.IntPtr,
-    ffi.IntPtr,
-    ffi.IntPtr,
-    ffi.IntPtr,
-    ffi.IntPtr,
-    ffi.IntPtr,
-    ffi.IntPtr);
+typedef NativeUndenaryOp = IntPtr Function(IntPtr, IntPtr, IntPtr, IntPtr,
+    IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr, IntPtr);
 typedef UndenaryOp = int Function(
     int, int, int, int, int, int, int, int, int, int, int);
 
@@ -275,17 +253,8 @@
   Expect.equals(66, sumManyIntsOdd(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11));
 }
 
-typedef NativeDoubleDecenaryOp = ffi.Double Function(
-    ffi.Double,
-    ffi.Double,
-    ffi.Double,
-    ffi.Double,
-    ffi.Double,
-    ffi.Double,
-    ffi.Double,
-    ffi.Double,
-    ffi.Double,
-    ffi.Double);
+typedef NativeDoubleDecenaryOp = Double Function(Double, Double, Double, Double,
+    Double, Double, Double, Double, Double, Double);
 typedef DoubleDecenaryOp = double Function(double, double, double, double,
     double, double, double, double, double, double);
 
@@ -297,27 +266,27 @@
       55.0, sumManyDoubles(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0));
 }
 
-typedef NativeVigesimalOp = ffi.Double Function(
-    ffi.IntPtr,
-    ffi.Float,
-    ffi.IntPtr,
-    ffi.Double,
-    ffi.IntPtr,
-    ffi.Float,
-    ffi.IntPtr,
-    ffi.Double,
-    ffi.IntPtr,
-    ffi.Float,
-    ffi.IntPtr,
-    ffi.Double,
-    ffi.IntPtr,
-    ffi.Float,
-    ffi.IntPtr,
-    ffi.Double,
-    ffi.IntPtr,
-    ffi.Float,
-    ffi.IntPtr,
-    ffi.Double);
+typedef NativeVigesimalOp = Double Function(
+    IntPtr,
+    Float,
+    IntPtr,
+    Double,
+    IntPtr,
+    Float,
+    IntPtr,
+    Double,
+    IntPtr,
+    Float,
+    IntPtr,
+    Double,
+    IntPtr,
+    Float,
+    IntPtr,
+    Double,
+    IntPtr,
+    Float,
+    IntPtr,
+    Double);
 typedef VigesimalOp = double Function(
     int,
     double,
@@ -350,21 +319,20 @@
           14.0, 15, 16.0, 17, 18.0, 19, 20.0));
 }
 
-typedef Int64PointerUnOp = ffi.Pointer<ffi.Int64> Function(
-    ffi.Pointer<ffi.Int64>);
+typedef Int64PointerUnOp = Pointer<Int64> Function(Pointer<Int64>);
 
 Int64PointerUnOp assign1337Index1 = ffiTestFunctions
     .lookupFunction<Int64PointerUnOp, Int64PointerUnOp>("Assign1337Index1");
 
 void testNativeFunctionPointer() {
-  ffi.Pointer<ffi.Int64> p2 = Pointer.allocate(count: 2);
-  p2.store(42);
-  p2.elementAt(1).store(1000);
-  ffi.Pointer<ffi.Int64> result = assign1337Index1(p2);
-  Expect.equals(1337, result.load<int>());
-  Expect.equals(1337, p2.elementAt(1).load<int>());
+  Pointer<Int64> p2 = allocate(count: 2);
+  p2.value = 42;
+  p2[1] = 1000;
+  Pointer<Int64> result = assign1337Index1(p2);
+  Expect.equals(1337, result.value);
+  Expect.equals(1337, p2[1]);
   Expect.equals(p2.elementAt(1).address, result.address);
-  p2.free();
+  free(p2);
 }
 
 void testNullInt() {
@@ -387,32 +355,32 @@
     .lookupFunction<Int64PointerUnOp, Int64PointerUnOp>("NullableInt64ElemAt1");
 
 void testNullPointers() {
-  Pointer<ffi.Int64> result = nullableInt64ElemAt1(ffi.nullptr.cast());
-  Expect.equals(result, ffi.nullptr);
+  Pointer<Int64> result = nullableInt64ElemAt1(nullptr);
+  Expect.equals(result, nullptr);
 
-  Pointer<ffi.Int64> p2 = Pointer.allocate(count: 2);
+  Pointer<Int64> p2 = allocate(count: 2);
   result = nullableInt64ElemAt1(p2);
-  Expect.notEquals(result, ffi.nullptr);
-  p2.free();
+  Expect.notEquals(result, nullptr);
+  free(p2);
 }
 
-typedef NativeFloatPointerToBool = ffi.Uint8 Function(ffi.Pointer<ffi.Float>);
-typedef FloatPointerToBool = int Function(ffi.Pointer<ffi.Float>);
+typedef NativeFloatPointerToBool = Uint8 Function(Pointer<Float>);
+typedef FloatPointerToBool = int Function(Pointer<Float>);
 
 FloatPointerToBool isRoughly1337 = ffiTestFunctions.lookupFunction<
     NativeFloatPointerToBool, FloatPointerToBool>("IsRoughly1337");
 
 void testFloatRounding() {
-  Pointer<ffi.Float> p2 = Pointer.allocate();
-  p2.store(1337.0);
+  Pointer<Float> p2 = allocate();
+  p2.value = 1337.0;
 
   int result = isRoughly1337(p2);
   Expect.equals(1, result);
 
-  p2.free();
+  free(p2);
 }
 
-typedef NativeFloatToVoid = ffi.Void Function(ffi.Float);
+typedef NativeFloatToVoid = Void Function(Float);
 typedef DoubleToVoid = void Function(double);
 
 DoubleToVoid devNullFloat = ffiTestFunctions
@@ -426,7 +394,7 @@
   Expect.isNull(result);
 }
 
-typedef NativeVoidToFloat = ffi.Float Function();
+typedef NativeVoidToFloat = Float Function();
 typedef VoidToDouble = double Function();
 
 VoidToDouble inventFloatValue = ffiTestFunctions
diff --git a/tests/ffi/highmem_32bit_test.dart b/tests/ffi/highmem_32bit_test.dart
new file mode 100644
index 0000000..eeee5fa
--- /dev/null
+++ b/tests/ffi/highmem_32bit_test.dart
@@ -0,0 +1,133 @@
+// 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:ffi';
+import 'dart:io';
+import 'dart:typed_data';
+
+import 'package:expect/expect.dart';
+
+import 'ffi_test_helpers.dart';
+
+// void* mmap(void* addr, size_t length,
+//            int prot, int flags,
+//            int fd, off_t offset)
+typedef MMapNative = Pointer<Uint8> Function(Pointer<Uint8> address, IntPtr len,
+    IntPtr prot, IntPtr flags, IntPtr fd, IntPtr offset);
+typedef MMap = Pointer<Uint8> Function(
+    Pointer<Uint8> address, int len, int prot, int flags, int fd, int offset);
+final mmap = processSymbols.lookupFunction<MMapNative, MMap>('mmap');
+
+// int munmap(void *addr, size_t length)
+typedef MUnMapNative = IntPtr Function(Pointer<Uint8> address, IntPtr len);
+typedef MUnMap = int Function(Pointer<Uint8> address, int len);
+final munmap = processSymbols.lookupFunction<MUnMapNative, MUnMap>('munmap');
+
+final processSymbols = DynamicLibrary.process();
+
+const int kProtRead = 1;
+const int kProtWrite = 2;
+
+const int kMapPrivate = 2;
+const int kMapFixed = 16;
+final int kMapAnonymous = Platform.isMacOS ? 0x1000 : 0x20;
+
+const int kMapFailed = -1;
+
+// On 32-bit platforms the upper 4 bytes should be ignored.
+const int kIgnoreBytesPositive = 0x1122334400000000;
+const int kIgnoreBytesNegative = 0xffddccbb00000000;
+
+void swapBytes(
+    Pointer<Uint8> memoryView, int indexOffset, int indexA, int indexB) {
+  final int oldA = memoryView[indexOffset + indexA];
+  memoryView[indexOffset + indexA] = memoryView[indexOffset + indexB];
+  memoryView[indexOffset + indexB] = oldA;
+}
+
+void testLoadsAndStores(int indexOffset, Pointer<Uint8> memory) {
+  for (int i = 0; i < 10; ++i) {
+    memory[indexOffset + i] = 10 + i;
+  }
+  Expect.listEquals(<int>[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
+      memory.offsetBy(indexOffset).asTypedList(10));
+
+  for (int i = 0; i < 9; ++i) {
+    swapBytes(memory, indexOffset + 0, i, i + 1);
+  }
+  Expect.listEquals(<int>[11, 12, 13, 14, 15, 16, 17, 18, 19, 10],
+      memory.offsetBy(indexOffset).asTypedList(10));
+  for (int i = 0; i < 9; ++i) {
+    swapBytes(memory, indexOffset + kIgnoreBytesPositive, i, i + 1);
+  }
+  Expect.listEquals(<int>[12, 13, 14, 15, 16, 17, 18, 19, 10, 11],
+      memory.offsetBy(indexOffset).asTypedList(10));
+  for (int i = 0; i < 9; ++i) {
+    swapBytes(memory, indexOffset + kIgnoreBytesNegative, i, i + 1);
+  }
+  Expect.listEquals(<int>[13, 14, 15, 16, 17, 18, 19, 10, 11, 12],
+      memory.offsetBy(indexOffset).asTypedList(10));
+}
+
+void testOnHighOrLowMemory(Pointer<Uint8> memory, int indexOffset) {
+  testLoadsAndStores(indexOffset, memory);
+  testLoadsAndStores(indexOffset, memory.offsetBy(5));
+  testLoadsAndStores(indexOffset, memory.offsetBy(-5));
+  testLoadsAndStores(indexOffset, memory.offsetBy(kIgnoreBytesPositive + 5));
+  testLoadsAndStores(indexOffset, memory.offsetBy(kIgnoreBytesNegative + 5));
+  testLoadsAndStores(indexOffset, memory.offsetBy(kIgnoreBytesPositive - 5));
+  testLoadsAndStores(indexOffset, memory.offsetBy(kIgnoreBytesNegative - 5));
+  final m2 = Pointer<Uint8>.fromAddress(kIgnoreBytesPositive + memory.address);
+  Expect.equals(memory, m2); //# 01: ok
+  Expect.equals(memory.address, m2.address); //# 01: ok
+  testLoadsAndStores(indexOffset, m2);
+  final m3 = Pointer<Uint8>.fromAddress(kIgnoreBytesNegative + memory.address);
+  Expect.equals(memory, m3); //# 01: ok
+  Expect.equals(memory.address, m3.address); //# 01: ok
+  testLoadsAndStores(indexOffset, m3);
+}
+
+const int kPageSize = 4096;
+
+withMMapedAddress(
+    Pointer<Uint8> fixedAddress, void fun(Pointer<Uint8> address)) {
+  final result = mmap(fixedAddress, kPageSize, kProtRead | kProtWrite,
+      kMapAnonymous | kMapFixed | kMapPrivate, 0, 0);
+  if (result.address == kMapFailed) {
+    throw 'Could not mmap @0x${fixedAddress.address.toRadixString(16)}!';
+  }
+  Expect.equals(fixedAddress, result); //# 01: ok
+  Expect.equals(fixedAddress.address, result.address); //# 01: ok
+  try {
+    fun(result);
+  } finally {
+    if (munmap(result, kPageSize) != 0) {
+      throw 'Failed to unmap memory!';
+    }
+  }
+}
+
+main() {
+  final bool is32BitProcess = sizeOf<Pointer<Uint8>>() == 4;
+
+  // User space processes usually have
+  //   * the lower 3 GB available on Linux/Android on 32bit OS
+  //   * full 4 GB available on Linux/Android on 64bit OS
+  //   * full 4 GB available on MacOS
+  // So we choose high and low addresses that fall into lower 3 GB.
+  if (is32BitProcess && !Platform.isWindows) {
+    final highMemoryAddress = Pointer<Uint8>.fromAddress(0xaaaa0000);
+    final lowMemoryAddress = Pointer<Uint8>.fromAddress(0x11110000);
+    withMMapedAddress(lowMemoryAddress, (Pointer<Uint8> lowMemory) {
+      withMMapedAddress(highMemoryAddress, (Pointer<Uint8> highMemory) {
+        testOnHighOrLowMemory(lowMemory, 2048);
+        testOnHighOrLowMemory(highMemory, 2048);
+        testOnHighOrLowMemory(
+            lowMemory, 2048 + highMemory.address - lowMemory.address);
+        testOnHighOrLowMemory(
+            highMemory, 2048 + lowMemory.address - highMemory.address);
+      });
+    });
+  }
+}
diff --git a/tests/ffi/object_gc_test.dart b/tests/ffi/object_gc_test.dart
index 165f9bc..de7d3f7 100644
--- a/tests/ffi/object_gc_test.dart
+++ b/tests/ffi/object_gc_test.dart
@@ -12,7 +12,6 @@
 
 import "package:expect/expect.dart";
 
-import 'utf8.dart';
 import 'dylib_utils.dart';
 
 DynamicLibrary ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
diff --git a/tests/ffi/regress_37100_test.dart b/tests/ffi/regress_37100_test.dart
index 19af367..a819503 100644
--- a/tests/ffi/regress_37100_test.dart
+++ b/tests/ffi/regress_37100_test.dart
@@ -10,7 +10,7 @@
 
 import 'dylib_utils.dart';
 
-class EVP_MD extends Struct<EVP_MD> {}
+class EVP_MD extends Struct {}
 
 DynamicLibrary ffiTestFunctions = dlopenPlatformSpecific("ffi_test_functions");
 
diff --git a/tests/ffi/regress_37254_test.dart b/tests/ffi/regress_37254_test.dart
index faf9897..27ab955 100644
--- a/tests/ffi/regress_37254_test.dart
+++ b/tests/ffi/regress_37254_test.dart
@@ -15,25 +15,25 @@
 // Note #2: When we switch to extension methods we will _only_ use the static
 //          type of the container.
 //
-// ===== a.store(b) ======
-// Does a.store(b), where a and b have specific static and dynamic types: run
+// ===== a.value = b ======
+// Does a.value = b, where a and b have specific static and dynamic types: run
 // fine, fail at compile time, or fail at runtime?
 // =======================
 //                  b     P<I>//P<I>   P<NT>//P<I>           P<NT>//P<NT>
 // a
 // P<P<I>>//P<P<I>>     1 ok         2 implicit downcast   3 implicit downcast
-//                                     of argument: ok       of argument: fail
-//                                                           at runtime
+//                                     of argument:          of argument:
+//                                     static error          static error
 //
 // P<P<NT>>//P<P<I>>    4 ok         5 ok                  6 fail at runtime
 //
 // P<P<NT>>//P<P<NT>>   7 ok         8 ok                  9 ok
 //
-// ====== final c = a.load() ======
-// What is the (inferred) static type and runtime type of `a.load()`. Note that
+// ====== final c = a.value ======
+// What is the (inferred) static type and runtime type of `a.value`. Note that
 // we assume extension method here: on Pointer<PointerT>> { Pointer<T> load(); }
 // ================================
-// a                    a.load()
+// a                    a.value
 //                      inferred static type*//runtime type
 // P<P<I>>//P<P<I>>     P<I>//P<I>
 //
@@ -43,8 +43,8 @@
 //
 // * The inferred static type when we get extension methods.
 //
-// ====== b = a.load() ======
-// What happens when we try to assign the result of a.load() to variable b with
+// ====== b = a.value ======
+// What happens when we try to assign the result of a.value to variable b with
 // a specific static type: runs fine, fails at compile time, or fails at runtime.
 // ==========================
 //                  b     P<I>                        P<NT>
@@ -63,201 +63,198 @@
 import 'dart:ffi';
 
 import "package:expect/expect.dart";
+import "package:ffi/ffi.dart";
 
-// ===== a.store(b) ======
+// ===== a.value = b ======
 // The tests follow table cells left to right, top to bottom.
 void store1() {
-  final Pointer<Pointer<Int8>> a = Pointer<Pointer<Int8>>.allocate();
-  final Pointer<Int8> b = Pointer<Int8>.allocate();
+  final Pointer<Pointer<Int8>> a = allocate<Pointer<Int8>>();
+  final Pointer<Int8> b = allocate<Int8>();
 
-  a.store(b);
+  a.value = b;
 
-  a.free();
-  b.free();
+  free(a);
+  free(b);
 }
 
 void store2() {
-  final Pointer<Pointer<Int8>> a = Pointer<Pointer<Int8>>.allocate();
+  final Pointer<Pointer<Int8>> a = allocate<Pointer<Int8>>();
   final Pointer<NativeType> b =
-      Pointer<Int8>.allocate(); // Reified Pointer<Int8> at runtime.
+      allocate<Int8>(); // Reified Pointer<Int8> at runtime.
 
   // Successful implicit downcast of argument at runtime.
   // Should succeed now, should statically be rejected when NNBD lands.
-  a.store(b);
+  a.value = b;
 
-  a.free();
-  b.free();
+  free(a);
+  free(b);
 }
 
 void store3() {
-  final Pointer<Pointer<Int8>> a = Pointer<Pointer<Int8>>.allocate();
-  final Pointer<NativeType> b =
-      Pointer<Int8>.allocate().cast<Pointer<NativeType>>();
+  final Pointer<Pointer<Int8>> a = allocate<Pointer<Int8>>();
+  final Pointer<NativeType> b = allocate<Int8>().cast<Pointer<NativeType>>();
 
   // Failing implicit downcast of argument at runtime.
   // Should fail now at runtime, should statically be rejected when NNBD lands.
   Expect.throws(() {
-    a.store(b);
+    a.value = b;
   });
 
-  a.free();
-  b.free();
+  free(a);
+  free(b);
 }
 
 void store4() {
   // Reified as Pointer<Pointer<Int8>> at runtime.
-  final Pointer<Pointer<NativeType>> a = Pointer<Pointer<Int8>>.allocate();
+  final Pointer<Pointer<NativeType>> a = allocate<Pointer<Int8>>();
 
-  final Pointer<Int8> b = Pointer<Int8>.allocate();
+  final Pointer<Int8> b = allocate<Int8>();
 
-  a.store(b);
+  a.value = b;
 
-  a.free();
-  b.free();
+  free(a);
+  free(b);
 }
 
 void store5() {
   // Reified as Pointer<Pointer<Int8>> at runtime.
-  final Pointer<Pointer<NativeType>> a = Pointer<Pointer<Int8>>.allocate();
+  final Pointer<Pointer<NativeType>> a = allocate<Pointer<Int8>>();
 
   final Pointer<NativeType> b =
-      Pointer<Int8>.allocate(); // Reified as Pointer<Int8> at runtime.
+      allocate<Int8>(); // Reified as Pointer<Int8> at runtime.
 
-  a.store(b);
+  a.value = b;
 
-  a.free();
-  b.free();
+  free(a);
+  free(b);
 }
 
 void store6() {
   // Reified as Pointer<Pointer<Int8>> at runtime.
-  final Pointer<Pointer<NativeType>> a = Pointer<Pointer<Int8>>.allocate();
-  final Pointer<NativeType> b =
-      Pointer<Int8>.allocate().cast<Pointer<NativeType>>();
+  final Pointer<Pointer<NativeType>> a = allocate<Pointer<Int8>>();
+  final Pointer<NativeType> b = allocate<Int8>().cast<Pointer<NativeType>>();
 
   // Fails on type check of argument.
   Expect.throws(() {
-    a.store(b);
+    a.value = b;
   });
 
-  a.free();
-  b.free();
+  free(a);
+  free(b);
 }
 
 void store7() {
-  final Pointer<Pointer<NativeType>> a =
-      Pointer<Pointer<NativeType>>.allocate();
-  final Pointer<Int8> b = Pointer<Int8>.allocate();
+  final Pointer<Pointer<NativeType>> a = allocate<Pointer<NativeType>>();
+  final Pointer<Int8> b = allocate<Int8>();
 
-  a.store(b);
+  a.value = b;
 
-  a.free();
-  b.free();
+  free(a);
+  free(b);
 }
 
 void store8() {
-  final Pointer<Pointer<NativeType>> a =
-      Pointer<Pointer<NativeType>>.allocate();
+  final Pointer<Pointer<NativeType>> a = allocate<Pointer<NativeType>>();
 
   // Reified as Pointer<Int8> at runtime.
-  final Pointer<NativeType> b = Pointer<Int8>.allocate();
+  final Pointer<NativeType> b = allocate<Int8>();
 
-  a.store(b);
+  a.value = b;
 
-  a.free();
-  b.free();
+  free(a);
+  free(b);
 }
 
 void store9() {
-  final Pointer<Pointer<NativeType>> a =
-      Pointer<Pointer<NativeType>>.allocate();
-  final Pointer<NativeType> b =
-      Pointer<Int8>.allocate().cast<Pointer<NativeType>>();
+  final Pointer<Pointer<NativeType>> a = allocate<Pointer<NativeType>>();
+  final Pointer<NativeType> b = allocate<Int8>().cast<Pointer<NativeType>>();
 
-  a.store(b);
+  a.value = b;
 
-  a.free();
-  b.free();
+  free(a);
+  free(b);
 }
 
-// ====== b = a.load() ======
+// ====== b = a.value ======
 // The tests follow table cells left to right, top to bottom.
 void load1() {
-  final Pointer<Pointer<Int8>> a = Pointer<Pointer<Int8>>.allocate();
+  final Pointer<Pointer<Int8>> a = allocate<Pointer<Int8>>();
 
-  Pointer<Int8> b = a.load();
+  Pointer<Int8> b = a.value;
   Expect.type<Pointer<Int8>>(b);
 
-  a.free();
+  free(a);
 }
 
 void load2() {
-  final Pointer<Pointer<Int8>> a = Pointer<Pointer<Int8>>.allocate();
+  final Pointer<Pointer<Int8>> a = allocate<Pointer<Int8>>();
 
-  Pointer<NativeType> b = a.load<Pointer<Int8>>();
+  Pointer<NativeType> b = a.value;
   Expect.type<Pointer<Int8>>(b);
 
-  a.free();
+  free(a);
 }
 
 void load3() {
   // Reified as Pointer<Pointer<Int8>> at runtime.
-  final Pointer<Pointer<NativeType>> a = Pointer<Pointer<Int8>>.allocate();
+  final Pointer<Pointer<NativeType>> a = allocate<Pointer<Int8>>();
 
-  Pointer<Int8> b = a.load<Pointer<NativeType>>();
+  Pointer<Int8> b = a.value;
   Expect.type<Pointer<Int8>>(b);
 
-  a.free();
+  free(a);
 }
 
 void load4() {
   // Reified as Pointer<Pointer<Int8>> at runtime.
-  final Pointer<Pointer<NativeType>> a = Pointer<Pointer<Int8>>.allocate();
+  final Pointer<Pointer<NativeType>> a = allocate<Pointer<Int8>>();
 
   // Return value runtime type is Pointer<Int8>.
-  Pointer<NativeType> b = a.load();
+  Pointer<NativeType> b = a.value;
   Expect.type<Pointer<Int8>>(b);
 
-  a.free();
+  free(a);
 }
 
 void load5() {
-  final Pointer<Pointer<NativeType>> a =
-      Pointer<Pointer<NativeType>>.allocate();
+  final Pointer<Pointer<NativeType>> a = allocate<Pointer<NativeType>>();
 
   // Failing implicit downcast of return value at runtime.
   // Should fail now at runtime, should statically be rejected when NNBD lands.
   Expect.throws(() {
-    Pointer<Int8> b = a.load<Pointer<NativeType>>();
+    Pointer<Int8> b = a.value;
   });
 
-  a.free();
+  free(a);
 }
 
 void load6() {
-  final Pointer<Pointer<NativeType>> a =
-      Pointer<Pointer<NativeType>>.allocate();
+  final Pointer<Pointer<NativeType>> a = allocate<Pointer<NativeType>>();
 
-  Pointer<NativeType> b = a.load();
+  Pointer<NativeType> b = a.value;
   Expect.type<Pointer<NativeType>>(b);
 
-  a.free();
+  free(a);
 }
 
 void main() {
-  store1();
-  store2();
-  store3();
-  store4();
-  store5();
-  store6();
-  store7();
-  store8();
-  store9();
-  load1();
-  load2();
-  load3();
-  load4();
-  load5();
-  load6();
+  // Trigger both the runtime entry and the IL in bytecode.
+  for (int i = 0; i < 100; i++) {
+    print(i);
+    store1();
+    store2();
+    store3();
+    store4();
+    store5();
+    store6();
+    store7();
+    store8();
+    store9();
+    load1();
+    load2();
+    load3();
+    load4();
+    load5();
+    load6();
+  }
 }
diff --git a/tests/ffi/regress_37511_test.dart b/tests/ffi/regress_37511_test.dart
index 03403e4..e2a2e70 100644
--- a/tests/ffi/regress_37511_test.dart
+++ b/tests/ffi/regress_37511_test.dart
@@ -36,7 +36,7 @@
   () => highAddressPointer.address,
   () => highAddressPointer.elementAt(1),
   () => highAddressPointer.offsetBy(1),
-  () => highAddressPointer.asExternalTypedData(),
+  () => highAddressPointer.asTypedList(1),
 
   // DynamicLibrary operations.
   doDlopen,
diff --git a/tests/ffi/snapshot_test.dart b/tests/ffi/snapshot_test.dart
index a3b7d22..a935a0d 100644
--- a/tests/ffi/snapshot_test.dart
+++ b/tests/ffi/snapshot_test.dart
@@ -5,9 +5,7 @@
 // Checks that the VM throws an appropriate exception when FFI objects are
 // passed between isolates.
 
-import 'dart:async';
 import 'dart:ffi';
-import 'dart:io';
 import 'dart:isolate';
 
 import 'package:expect/expect.dart';
diff --git a/tests/ffi/static_checks_test.dart b/tests/ffi/static_checks_test.dart
index 22d5256..3c60703 100644
--- a/tests/ffi/static_checks_test.dart
+++ b/tests/ffi/static_checks_test.dart
@@ -8,8 +8,9 @@
 
 library FfiTest;
 
-import 'dart:ffi' as ffi;
-import 'dart:ffi' show Pointer;
+import 'dart:ffi';
+
+import "package:ffi/ffi.dart";
 
 import 'dylib_utils.dart';
 
@@ -47,30 +48,30 @@
   testNativeFunctionSignatureInvalidOptionalPositional();
 }
 
-typedef Int8UnOp = ffi.Int8 Function(ffi.Int8);
+typedef Int8UnOp = Int8 Function(Int8);
 typedef IntUnOp = int Function(int);
 
 void testGetGeneric() {
-  int generic(ffi.Pointer p) {
+  int generic(Pointer p) {
     int result;
-    result = p.load<int>(); //# 20: compile-time error
+    result = p.value; //# 20: compile-time error
     return result;
   }
 
-  ffi.Pointer<ffi.Int8> p = Pointer.allocate();
-  p.store(123);
-  ffi.Pointer loseType = p;
+  Pointer<Int8> p = allocate();
+  p.value = 123;
+  Pointer loseType = p;
   generic(loseType);
-  p.free();
+  free(p);
 }
 
 void testGetGeneric2() {
   T generic<T extends Object>() {
-    Pointer<ffi.Int8> p = Pointer.allocate();
-    p.store(123);
+    Pointer<Int8> p = allocate();
+    p.value = 123;
     T result;
-    result = p.load<T>(); //# 21: compile-time error
-    p.free();
+    result = p.value; //# 21: compile-time error
+    free(p);
     return result;
   }
 
@@ -78,92 +79,92 @@
 }
 
 void testGetVoid() {
-  ffi.Pointer<ffi.IntPtr> p1 = Pointer.allocate();
-  ffi.Pointer<ffi.Void> p2 = p1.cast();
+  Pointer<IntPtr> p1 = allocate();
+  Pointer<Void> p2 = p1.cast();
 
-  p2.load<int>(); //# 22: compile-time error
+  p2.value; //# 22: compile-time error
 
-  p1.free();
+  free(p1);
 }
 
 void testGetNativeFunction() {
-  Pointer<ffi.NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
-  IntUnOp f = p.load(); //# 23: compile-time error
+  Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
+  IntUnOp f = p.value; //# 23: compile-time error
 }
 
 void testGetNativeType() {
-  // Is it possible to obtain a ffi.Pointer<ffi.NativeType> at all?
+  // Is it possible to obtain a Pointer<NativeType> at all?
 }
 
 void testGetTypeMismatch() {
-  ffi.Pointer<ffi.Pointer<ffi.Int16>> p = Pointer.allocate();
-  ffi.Pointer<ffi.Int16> typedNull = ffi.nullptr.cast();
-  p.store(typedNull);
+  Pointer<Pointer<Int16>> p = allocate();
+  Pointer<Int16> typedNull = nullptr;
+  p.value = typedNull;
 
   // this fails to compile due to type mismatch
-  ffi.Pointer<ffi.Int8> p2 = p.load(); //# 25: compile-time error
+  Pointer<Int8> p2 = p.value; //# 25: compile-time error
 
-  p.free();
+  free(p);
 }
 
 void testSetGeneric() {
-  void generic(ffi.Pointer p) {
-    p.store(123); //# 26: compile-time error
+  void generic(Pointer p) {
+    p.value = 123; //# 26: compile-time error
   }
 
-  ffi.Pointer<ffi.Int8> p = Pointer.allocate();
-  p.store(123);
-  ffi.Pointer loseType = p;
+  Pointer<Int8> p = allocate();
+  p.value = 123;
+  Pointer loseType = p;
   generic(loseType);
-  p.free();
+  free(p);
 }
 
 void testSetGeneric2() {
   void generic<T extends Object>(T arg) {
-    ffi.Pointer<ffi.Int8> p = Pointer.allocate();
-    p.store(arg); //# 27: compile-time error
-    p.free();
+    Pointer<Int8> p = allocate();
+    p.value = arg; //# 27: compile-time error
+    free(p);
   }
 
   generic<int>(123);
 }
 
 void testSetVoid() {
-  ffi.Pointer<ffi.IntPtr> p1 = Pointer.allocate();
-  ffi.Pointer<ffi.Void> p2 = p1.cast();
+  Pointer<IntPtr> p1 = allocate();
+  Pointer<Void> p2 = p1.cast();
 
-  p2.store(1234); //# 28: compile-time error
+  p2.value = 1234; //# 28: compile-time error
 
-  p1.free();
+  free(p1);
 }
 
 void testSetNativeFunction() {
-  Pointer<ffi.NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
+  Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
   IntUnOp f = (a) => a + 1;
-  p.store(f); //# 29: compile-time error
+  p.value = f; //# 29: compile-time error
 }
 
 void testSetNativeType() {
-  // Is it possible to obtain a ffi.Pointer<ffi.NativeType> at all?
+  // Is it possible to obtain a Pointer<NativeType> at all?
 }
 
 void testSetTypeMismatch() {
   // the pointer to pointer types must match up
-  ffi.Pointer<ffi.Int8> pHelper = Pointer.allocate();
-  pHelper.store(123);
+  Pointer<Int8> pHelper = allocate();
+  pHelper.value = 123;
 
-  ffi.Pointer<ffi.Pointer<ffi.Int16>> p = Pointer.allocate();
+  Pointer<Pointer<Int16>> p = allocate();
 
   // this fails to compile due to type mismatch
-  p.store(pHelper); //# 40: compile-time error
+  p.value = pHelper; //# 40: compile-time error
 
-  pHelper.free();
-  p.free();
+  free(pHelper);
+  free(p);
 }
 
 void testAsFunctionGeneric() {
   T generic<T extends Function>() {
-    ffi.Pointer<ffi.NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
+    Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
     Function f;
     f = p.asFunction<T>(); //# 11: compile-time error
     return f;
@@ -173,29 +174,29 @@
 }
 
 void testAsFunctionGeneric2() {
-  generic(ffi.Pointer<ffi.NativeFunction> p) {
+  generic(Pointer<NativeFunction> p) {
     Function f;
     f = p.asFunction<IntUnOp>(); //# 12: compile-time error
     return f;
   }
 
-  ffi.Pointer<ffi.NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
+  Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
   generic(p);
 }
 
 void testAsFunctionWrongNativeFunctionSignature() {
-  ffi.Pointer<ffi.NativeFunction<IntUnOp>> p;
+  Pointer<NativeFunction<IntUnOp>> p;
   Function f = p.asFunction<IntUnOp>(); //# 13: compile-time error
 }
 
 typedef IntBinOp = int Function(int, int);
 
 void testAsFunctionTypeMismatch() {
-  ffi.Pointer<ffi.NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
+  Pointer<NativeFunction<Int8UnOp>> p = Pointer.fromAddress(1337);
   IntBinOp f = p.asFunction(); //# 14: compile-time error
 }
 
-typedef NativeDoubleUnOp = ffi.Double Function(ffi.Double);
+typedef NativeDoubleUnOp = Double Function(Double);
 typedef DoubleUnOp = double Function(double);
 
 double myTimesThree(double d) => d * 3;
@@ -203,9 +204,9 @@
 int myTimesFour(int i) => i * 4;
 
 void testFromFunctionGeneric() {
-  ffi.Pointer<ffi.NativeFunction> generic<T extends Function>(T f) {
-    ffi.Pointer<ffi.NativeFunction<NativeDoubleUnOp>> result;
-    result = ffi.fromFunction(f); //# 70: compile-time error
+  Pointer<NativeFunction> generic<T extends Function>(T f) {
+    Pointer<NativeFunction<NativeDoubleUnOp>> result;
+    result = Pointer.fromFunction(f); //# 70: compile-time error
     return result;
   }
 
@@ -213,9 +214,9 @@
 }
 
 void testFromFunctionGeneric2() {
-  ffi.Pointer<ffi.NativeFunction<T>> generic<T extends Function>() {
-    ffi.Pointer<ffi.NativeFunction<T>> result;
-    result = ffi.fromFunction(myTimesThree); //# 71: compile-time error
+  Pointer<NativeFunction<T>> generic<T extends Function>() {
+    Pointer<NativeFunction<T>> result;
+    result = Pointer.fromFunction(myTimesThree); //# 71: compile-time error
     return result;
   }
 
@@ -223,18 +224,18 @@
 }
 
 void testFromFunctionWrongNativeFunctionSignature() {
-  ffi.fromFunction<IntUnOp>(myTimesFour); //# 72: compile-time error
+  Pointer.fromFunction<IntUnOp>(myTimesFour); //# 72: compile-time error
 }
 
 void testFromFunctionTypeMismatch() {
-  ffi.Pointer<ffi.NativeFunction<NativeDoubleUnOp>> p;
-  p = ffi.fromFunction(myTimesFour); //# 73: compile-time error
+  Pointer<NativeFunction<NativeDoubleUnOp>> p;
+  p = Pointer.fromFunction(myTimesFour); //# 73: compile-time error
 }
 
 void testFromFunctionClosure() {
   DoubleUnOp someClosure = (double z) => z / 27.0;
-  ffi.Pointer<ffi.NativeFunction<NativeDoubleUnOp>> p;
-  p = ffi.fromFunction(someClosure); //# 74: compile-time error
+  Pointer<NativeFunction<NativeDoubleUnOp>> p;
+  p = Pointer.fromFunction(someClosure); //# 74: compile-time error
 }
 
 class X {
@@ -245,17 +246,18 @@
 
 void testFromFunctionTearOff() {
   fld = X().tearoff;
-  ffi.Pointer<ffi.NativeFunction<NativeDoubleUnOp>> p;
-  p = ffi.fromFunction(fld); //# 75: compile-time error
+  Pointer<NativeFunction<NativeDoubleUnOp>> p;
+  p = Pointer.fromFunction(fld); //# 75: compile-time error
 }
 
 void testFromFunctionAbstract() {
-  ffi.Pointer.fromFunction<Function>(testFromFunctionAbstract);  //# 76: compile-time error
+  Pointer.fromFunction<Function>(//# 76: compile-time error
+      testFromFunctionAbstract); //# 76: compile-time error
 }
 
 void testLookupFunctionGeneric() {
   Function generic<T extends Function>() {
-    ffi.DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
+    DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
     Function result;
     result = l.lookupFunction<T, DoubleUnOp>("cos"); //# 15: compile-time error
     return result;
@@ -266,7 +268,7 @@
 
 void testLookupFunctionGeneric2() {
   Function generic<T extends Function>() {
-    ffi.DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
+    DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
     Function result;
     result = //# 16: compile-time error
         l.lookupFunction<NativeDoubleUnOp, T>("cos"); //# 16: compile-time error
@@ -277,40 +279,40 @@
 }
 
 void testLookupFunctionWrongNativeFunctionSignature() {
-  ffi.DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
+  DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
   l.lookupFunction<IntUnOp, IntUnOp>("cos"); //# 17: compile-time error
 }
 
 void testLookupFunctionTypeMismatch() {
-  ffi.DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
+  DynamicLibrary l = dlopenPlatformSpecific("ffi_test_dynamic_library");
   l.lookupFunction<NativeDoubleUnOp, IntUnOp>("cos"); //# 18: compile-time error
 }
 
 // TODO(dacoharkes): make the next 4 test compile errors
-typedef Invalid1 = int Function(ffi.Int8);
-typedef Invalid2 = ffi.Int8 Function(int);
-typedef Invalid3 = ffi.Int8 Function({ffi.Int8 named});
-typedef Invalid4 = ffi.Int8 Function([ffi.Int8 positional]);
+typedef Invalid1 = int Function(Int8);
+typedef Invalid2 = Int8 Function(int);
+typedef Invalid3 = Int8 Function({Int8 named});
+typedef Invalid4 = Int8 Function([Int8 positional]);
 
 void testNativeFunctionSignatureInvalidReturn() {
-  // ffi.Pointer<ffi.NativeFunction<Invalid1>> p = ffi.fromAddress(999);
+  // Pointer<NativeFunction<Invalid1>> p = fromAddress(999);
 }
 
 void testNativeFunctionSignatureInvalidParam() {
-  // ffi.Pointer<ffi.NativeFunction<Invalid2>> p = ffi.fromAddress(999);
+  // Pointer<NativeFunction<Invalid2>> p = fromAddress(999);
 }
 
 void testNativeFunctionSignatureInvalidOptionalNamed() {
-  // ffi.Pointer<ffi.NativeFunction<Invalid3>> p = ffi.fromAddress(999);
+  // Pointer<NativeFunction<Invalid3>> p = fromAddress(999);
 }
 
 void testNativeFunctionSignatureInvalidOptionalPositional() {
-  // ffi.Pointer<ffi.NativeFunction<Invalid4>> p = ffi.fromAddress(999);
+  // Pointer<NativeFunction<Invalid4>> p = fromAddress(999);
 }
 
 // error on missing field annotation
-class TestStruct extends ffi.Struct<TestStruct> {
-  @ffi.Double()
+class TestStruct extends Struct {
+  @Double()
   double x;
 
   double y; //# 50: compile-time error
@@ -320,55 +322,52 @@
 class TestStruct3 extends TestStruct {} //# 52: compile-time error
 
 // error on double annotation
-class TestStruct4 extends ffi.Struct<TestStruct4> {
-  @ffi.Double()
-  @ffi.Double() //# 53: compile-time error
+class TestStruct4 extends Struct {
+  @Double()
+  @Double() //# 53: compile-time error
   double z;
 }
 
 // error on annotation not matching up
-class TestStruct5 extends ffi.Struct<TestStruct5> {
-  @ffi.Int64() //# 54: compile-time error
+class TestStruct5 extends Struct {
+  @Int64() //# 54: compile-time error
   double z; //# 54: compile-time error
 }
 
 // error on annotation not matching up
-class TestStruct6 extends ffi.Struct<TestStruct6> {
-  @ffi.Void() //# 55: compile-time error
+class TestStruct6 extends Struct {
+  @Void() //# 55: compile-time error
   double z; //# 55: compile-time error
 }
 
 // error on annotation not matching up
-class TestStruct7 extends ffi.Struct<TestStruct7> {
-  @ffi.NativeType() //# 56: compile-time error
+class TestStruct7 extends Struct {
+  @NativeType() //# 56: compile-time error
   double z; //# 56: compile-time error
 }
 
 // error on field initializer on field
-class TestStruct8 extends ffi.Struct<TestStruct8> {
-  @ffi.Double() //# 57: compile-time error
+class TestStruct8 extends Struct {
+  @Double() //# 57: compile-time error
   double z = 10.0; //# 57: compile-time error
 }
 
 // error on field initializer in constructor
-class TestStruct9 extends ffi.Struct<TestStruct9> {
-  @ffi.Double()
+class TestStruct9 extends Struct {
+  @Double()
   double z;
 
   TestStruct9() : z = 0.0 {} //# 58: compile-time error
 }
 
-// A struct "C" must extend "Struct<C>", not "Struct<AnythingElse>".
-class TestStruct10 extends ffi.Struct<ffi.Int8> {} //# 59: compile-time error
-
 // Struct classes may not be generic.
 class TestStruct11<T> extends //# 60: compile-time error
-    ffi.Struct<TestStruct11<dynamic>> {} //# 60: compile-time error
+    Struct<TestStruct11<dynamic>> {} //# 60: compile-time error
 
 // Structs may not appear inside structs (currently, there is no suitable
 // annotation).
-class TestStruct12 extends ffi.Struct<TestStruct12> {
-  @ffi.Pointer //# 61: compile-time error
+class TestStruct12 extends Struct {
+  @Pointer //# 61: compile-time error
   TestStruct9 struct; //# 61: compile-time error
 }
 
@@ -377,78 +376,78 @@
 }
 
 // Structs fields may have other annotations.
-class TestStruct13 extends ffi.Struct<TestStruct13> {
+class TestStruct13 extends Struct {
   @DummyAnnotation()
-  @ffi.Double()
+  @Double()
   double z;
 }
 
 // Cannot extend native types.
 
-class ENativeType extends ffi.NativeType {} //# 90: compile-time error
+class ENativeType extends NativeType {} //# 90: compile-time error
 
-class EInt8 extends ffi.Int8 {} //# 91: compile-time error
+class EInt8 extends Int8 {} //# 91: compile-time error
 
-class EInt16 extends ffi.Int16 {} //# 92: compile-time error
+class EInt16 extends Int16 {} //# 92: compile-time error
 
-class EInt32 extends ffi.Int32 {} //# 93: compile-time error
+class EInt32 extends Int32 {} //# 93: compile-time error
 
-class EInt64 extends ffi.Int64 {} //# 94: compile-time error
+class EInt64 extends Int64 {} //# 94: compile-time error
 
-class EUint8 extends ffi.Uint8 {} //# 95: compile-time error
+class EUint8 extends Uint8 {} //# 95: compile-time error
 
-class EUint16 extends ffi.Uint16 {} //# 96: compile-time error
+class EUint16 extends Uint16 {} //# 96: compile-time error
 
-class EUint32 extends ffi.Uint32 {} //# 97: compile-time error
+class EUint32 extends Uint32 {} //# 97: compile-time error
 
-class EUint64 extends ffi.Uint64 {} //# 98: compile-time error
+class EUint64 extends Uint64 {} //# 98: compile-time error
 
-class EIntPtr extends ffi.IntPtr {} //# 99: compile-time error
+class EIntPtr extends IntPtr {} //# 99: compile-time error
 
-class EFloat extends ffi.Float {} //# 910: compile-time error
+class EFloat extends Float {} //# 910: compile-time error
 
-class EDouble extends ffi.Double {} //# 911: compile-time error
+class EDouble extends Double {} //# 911: compile-time error
 
-class EVoid extends ffi.Void {} //# 912: compile-time error
+class EVoid extends Void {} //# 912: compile-time error
 
-class ENativeFunction extends ffi.NativeFunction {} //# 913: compile-time error
+class ENativeFunction extends NativeFunction {} //# 913: compile-time error
 
-class EPointer extends ffi.Pointer {} //# 914: compile-time error
+class EPointer extends Pointer {} //# 914: compile-time error
 
 // Cannot implement native natives or Struct.
 
 // Cannot extend native types.
 
-class INativeType implements ffi.NativeType {} //# 80: compile-time error
+class INativeType implements NativeType {} //# 80: compile-time error
 
-class IInt8 implements ffi.Int8 {} //# 81: compile-time error
+class IInt8 implements Int8 {} //# 81: compile-time error
 
-class IInt16 implements ffi.Int16 {} //# 82: compile-time error
+class IInt16 implements Int16 {} //# 82: compile-time error
 
-class IInt32 implements ffi.Int32 {} //# 83: compile-time error
+class IInt32 implements Int32 {} //# 83: compile-time error
 
-class IInt64 implements ffi.Int64 {} //# 84: compile-time error
+class IInt64 implements Int64 {} //# 84: compile-time error
 
-class IUint8 implements ffi.Uint8 {} //# 85: compile-time error
+class IUint8 implements Uint8 {} //# 85: compile-time error
 
-class IUint16 implements ffi.Uint16 {} //# 86: compile-time error
+class IUint16 implements Uint16 {} //# 86: compile-time error
 
-class IUint32 implements ffi.Uint32 {} //# 87: compile-time error
+class IUint32 implements Uint32 {} //# 87: compile-time error
 
-class IUint64 implements ffi.Uint64 {} //# 88: compile-time error
+class IUint64 implements Uint64 {} //# 88: compile-time error
 
-class IIntPtr implements ffi.IntPtr {} //# 88: compile-time error
+class IIntPtr implements IntPtr {} //# 88: compile-time error
 
-class IFloat implements ffi.Float {} //# 810: compile-time error
+class IFloat implements Float {} //# 810: compile-time error
 
-class IDouble implements ffi.Double {} //# 811: compile-time error
+class IDouble implements Double {} //# 811: compile-time error
 
-class IVoid implements ffi.Void {} //# 812: compile-time error
+class IVoid implements Void {} //# 812: compile-time error
 
 class INativeFunction //# 813: compile-time error
     implements //# 813: compile-time error
-        ffi.NativeFunction {} //# 813: compile-time error
+        NativeFunction {} //# 813: compile-time error
 
-class IPointer implements ffi.Pointer {} //# 814: compile-time error
+class IPointer implements Pointer {} //# 814: compile-time error
 
-class IStruct implements ffi.Struct {} //# 815: compile-time error
+class IStruct implements Struct {} //# 815: compile-time error
diff --git a/tests/ffi/structs_test.dart b/tests/ffi/structs_test.dart
index ef6c86e..669e837 100644
--- a/tests/ffi/structs_test.dart
+++ b/tests/ffi/structs_test.dart
@@ -11,10 +11,11 @@
 import 'dart:ffi';
 
 import "package:expect/expect.dart";
+import "package:ffi/ffi.dart";
 
+import 'ffi_test_helpers.dart';
 import 'coordinate_bare.dart' as bare;
 import 'coordinate.dart';
-import 'utf8.dart';
 
 void main() {
   for (int i = 0; i < 100; i++) {
@@ -29,73 +30,74 @@
 
 /// allocates each coordinate separately in c memory
 void testStructAllocate() {
-  Pointer<Coordinate> c1 =
-      Coordinate.allocate(10.0, 10.0, nullptr.cast()).addressOf;
+  Pointer<Coordinate> c1 = Coordinate.allocate(10.0, 10.0, nullptr).addressOf;
   Pointer<Coordinate> c2 = Coordinate.allocate(20.0, 20.0, c1).addressOf;
   Pointer<Coordinate> c3 = Coordinate.allocate(30.0, 30.0, c2).addressOf;
-  c1.load<Coordinate>().next = c3;
+  c1.ref.next = c3;
 
-  Coordinate currentCoordinate = c1.load();
+  Coordinate currentCoordinate = c1.ref;
   Expect.equals(10.0, currentCoordinate.x);
-  currentCoordinate = currentCoordinate.next.load();
+  currentCoordinate = currentCoordinate.next.ref;
   Expect.equals(30.0, currentCoordinate.x);
-  currentCoordinate = currentCoordinate.next.load();
+  currentCoordinate = currentCoordinate.next.ref;
   Expect.equals(20.0, currentCoordinate.x);
-  currentCoordinate = currentCoordinate.next.load();
+  currentCoordinate = currentCoordinate.next.ref;
   Expect.equals(10.0, currentCoordinate.x);
 
-  c1.free();
-  c2.free();
-  c3.free();
+  free(c1);
+  free(c2);
+  free(c3);
 }
 
 /// allocates coordinates consecutively in c memory
 void testStructFromAddress() {
-  Pointer<Coordinate> c1 = Pointer.allocate(count: 3);
+  Pointer<Coordinate> c1 = allocate(count: 3);
   Pointer<Coordinate> c2 = c1.elementAt(1);
   Pointer<Coordinate> c3 = c1.elementAt(2);
-  c1.load<Coordinate>().x = 10.0;
-  c1.load<Coordinate>().y = 10.0;
-  c1.load<Coordinate>().next = c3;
-  c2.load<Coordinate>().x = 20.0;
-  c2.load<Coordinate>().y = 20.0;
-  c2.load<Coordinate>().next = c1;
-  c3.load<Coordinate>().x = 30.0;
-  c3.load<Coordinate>().y = 30.0;
-  c3.load<Coordinate>().next = c2;
+  c1.ref
+    ..x = 10.0
+    ..y = 10.0
+    ..next = c3;
+  c2.ref
+    ..x = 20.0
+    ..y = 20.0
+    ..next = c1;
+  c3.ref
+    ..x = 30.0
+    ..y = 30.0
+    ..next = c2;
 
-  Coordinate currentCoordinate = c1.load();
+  Coordinate currentCoordinate = c1.ref;
   Expect.equals(10.0, currentCoordinate.x);
-  currentCoordinate = currentCoordinate.next.load();
+  currentCoordinate = currentCoordinate.next.ref;
   Expect.equals(30.0, currentCoordinate.x);
-  currentCoordinate = currentCoordinate.next.load();
+  currentCoordinate = currentCoordinate.next.ref;
   Expect.equals(20.0, currentCoordinate.x);
-  currentCoordinate = currentCoordinate.next.load();
+  currentCoordinate = currentCoordinate.next.ref;
   Expect.equals(10.0, currentCoordinate.x);
 
-  c1.free();
+  free(c1);
 }
 
 void testStructWithNulls() {
   Pointer<Coordinate> coordinate =
-      Coordinate.allocate(10.0, 10.0, nullptr.cast<Coordinate>()).addressOf;
-  Expect.equals(coordinate.load<Coordinate>().next, nullptr);
-  coordinate.load<Coordinate>().next = coordinate;
-  Expect.notEquals(coordinate.load<Coordinate>().next, nullptr);
-  coordinate.load<Coordinate>().next = nullptr.cast();
-  Expect.equals(coordinate.load<Coordinate>().next, nullptr);
-  coordinate.free();
+      Coordinate.allocate(10.0, 10.0, nullptr).addressOf;
+  Expect.equals(coordinate.ref.next, nullptr);
+  coordinate.ref.next = coordinate;
+  Expect.notEquals(coordinate.ref.next, nullptr);
+  coordinate.ref.next = nullptr;
+  Expect.equals(coordinate.ref.next, nullptr);
+  free(coordinate);
 }
 
 void testBareStruct() {
   int structSize = sizeOf<Double>() * 2 + sizeOf<IntPtr>();
-  bare.Coordinate c1 = Pointer<Uint8>.allocate(count: structSize * 3)
-      .cast<bare.Coordinate>()
-      .load();
+  bare.Coordinate c1 =
+      allocate<Uint8>(count: structSize * 3).cast<bare.Coordinate>().ref;
   bare.Coordinate c2 =
-      c1.addressOf.offsetBy(structSize).cast<bare.Coordinate>().load();
+      c1.addressOf.offsetBy(structSize).cast<bare.Coordinate>().ref;
   bare.Coordinate c3 =
-      c1.addressOf.offsetBy(structSize * 2).cast<bare.Coordinate>().load();
+      c1.addressOf.offsetBy(structSize * 2).cast<bare.Coordinate>().ref;
   c1.x = 10.0;
   c1.y = 10.0;
   c1.next = c3.addressOf;
@@ -108,26 +110,26 @@
 
   bare.Coordinate currentCoordinate = c1;
   Expect.equals(10.0, currentCoordinate.x);
-  currentCoordinate = currentCoordinate.next.load();
+  currentCoordinate = currentCoordinate.next.ref;
   Expect.equals(30.0, currentCoordinate.x);
-  currentCoordinate = currentCoordinate.next.load();
+  currentCoordinate = currentCoordinate.next.ref;
   Expect.equals(20.0, currentCoordinate.x);
-  currentCoordinate = currentCoordinate.next.load();
+  currentCoordinate = currentCoordinate.next.ref;
   Expect.equals(10.0, currentCoordinate.x);
 
-  c1.addressOf.free();
+  free(c1.addressOf);
 }
 
 void testTypeTest() {
-  Coordinate c = Coordinate.allocate(10, 10, nullptr.cast<Coordinate>());
+  Coordinate c = Coordinate.allocate(10, 10, nullptr);
   Expect.isTrue(c is Struct);
-  Expect.isTrue(c is Struct<Coordinate>);
-  c.addressOf.free();
+  Expect.isTrue(c.addressOf is Pointer<Coordinate>);
+  free(c.addressOf);
 }
 
 void testUtf8() {
   final String test = 'Hasta Mañana';
   final Pointer<Utf8> medium = Utf8.toUtf8(test);
   Expect.equals(test, Utf8.fromUtf8(medium));
-  medium.free();
+  free(medium);
 }
diff --git a/tests/ffi/utf8.dart b/tests/ffi/utf8.dart
deleted file mode 100644
index cdaccf8..0000000
--- a/tests/ffi/utf8.dart
+++ /dev/null
@@ -1,37 +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.
-
-library Utf8;
-
-import 'dart:convert';
-import 'dart:ffi' as ffi;
-import 'dart:ffi' show Pointer;
-
-/// Sample non-struct Pointer wrapper for dart:ffi library.
-class Utf8 extends ffi.Struct<Utf8> {
-  @ffi.Uint8()
-  int char;
-
-  static String fromUtf8(Pointer<Utf8> str) {
-    List<int> units = [];
-    int len = 0;
-    while (true) {
-      int char = str.elementAt(len++).load<Utf8>().char;
-      if (char == 0) break;
-      units.add(char);
-    }
-    return Utf8Decoder().convert(units);
-  }
-
-  static Pointer<Utf8> toUtf8(String s) {
-    List<int> units = Utf8Encoder().convert(s);
-    Pointer<Utf8> result =
-        Pointer<Utf8>.allocate(count: units.length + 1).cast();
-    for (int i = 0; i < units.length; i++) {
-      result.elementAt(i).load<Utf8>().char = units[i];
-    }
-    result.elementAt(units.length).load<Utf8>().char = 0;
-    return result;
-  }
-}
diff --git a/tests/ffi/very_large_struct.dart b/tests/ffi/very_large_struct.dart
index 36202f6..ca29143 100644
--- a/tests/ffi/very_large_struct.dart
+++ b/tests/ffi/very_large_struct.dart
@@ -5,7 +5,7 @@
 import 'dart:ffi';
 
 /// Large sample struct for dart:ffi library.
-class VeryLargeStruct extends Struct<VeryLargeStruct> {
+class VeryLargeStruct extends Struct {
   @Int8()
   int a;
 
diff --git a/tests/language_2/extension_methods/static_extension_bounds_error_test.dart b/tests/language_2/extension_methods/static_extension_bounds_error_test.dart
index e0529dd..67c9544 100644
--- a/tests/language_2/extension_methods/static_extension_bounds_error_test.dart
+++ b/tests/language_2/extension_methods/static_extension_bounds_error_test.dart
@@ -39,13 +39,13 @@
   E1(s).e1;
 //^^
 // [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
-//      ^
+//^
 // [cfe] Inferred type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'E1|get#e1'.
   E1<String>(s).e1;
 //   ^^^^^^
 // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS
-//              ^
-// [cfe] Inferred type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'E1|get#e1'.
+//^
+// [cfe] Type argument 'String' doesn't conform to the bound 'num' of the type variable 'T' on 'E1|get#e1'.
 
   // Inferred types of int and double are ok
   i.e1;
@@ -63,13 +63,13 @@
   E2(s).e2;
 //^^
 // [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
-//      ^
+//^
 // [cfe] Inferred type argument 'String' doesn't conform to the bound 'S' of the type variable 'T' on 'E2|get#e2'.
   E2<String, num>(s).e2;
 //   ^^^^^^
 // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS
-//                   ^
-// [cfe] Inferred type argument 'String' doesn't conform to the bound 'S' of the type variable 'T' on 'E2|get#e2'.
+//^
+// [cfe] Type argument 'String' doesn't conform to the bound 'S' of the type variable 'T' on 'E2|get#e2'.
 
   // Inferred types of int and double are ok
   i.e2;
@@ -84,7 +84,7 @@
   s.f3(3);
 //  ^^
 // [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
-// [cfe] Type argument 'int' doesn't conform to the bound 'T' of the type variable 'S' on 'E3|f3'.
+// [cfe] Inferred type argument 'int' doesn't conform to the bound 'T' of the type variable 'S' on 'E3|f3'.
   E3(s).f3(3);
 //      ^^
 // [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
@@ -104,7 +104,7 @@
   d.f3(3);
 //  ^^
 // [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
-// [cfe] Type argument 'int' doesn't conform to the bound 'T' of the type variable 'S' on 'E3|f3'.
+// [cfe] Inferred type argument 'int' doesn't conform to the bound 'T' of the type variable 'S' on 'E3|f3'.
   E3(d).f3(3);
 //      ^^
 // [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
@@ -130,11 +130,11 @@
   E4(superRec).e4;
 //^^
 // [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
-//             ^
+//^
 // [cfe] Inferred type argument 'Rec<dynamic>' doesn't conform to the bound 'Rec<T>' of the type variable 'T' on 'E4|get#e4'.
   E4<Rec<dynamic>>(superRec).e4;
 //   ^^^^^^^^^^^^
 // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS
-//                           ^
-// [cfe] Inferred type argument 'Rec<dynamic>' doesn't conform to the bound 'Rec<T>' of the type variable 'T' on 'E4|get#e4'.
+//^
+// [cfe] Type argument 'Rec<dynamic>' doesn't conform to the bound 'Rec<T>' of the type variable 'T' on 'E4|get#e4'.
 }
diff --git a/tests/language_2/extension_methods/static_extension_internal_name_conflict_error_test.dart b/tests/language_2/extension_methods/static_extension_internal_name_conflict_error_test.dart
index 8189ae8..a284784 100644
--- a/tests/language_2/extension_methods/static_extension_internal_name_conflict_error_test.dart
+++ b/tests/language_2/extension_methods/static_extension_internal_name_conflict_error_test.dart
@@ -84,7 +84,6 @@
   static void set field2(int value) {}
   //              ^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
-  // [cfe] unspecified
 }
 
 // Check instance members colliding with instance members (of the same kind).
@@ -121,9 +120,11 @@
   static int get property2 => 1;
   //             ^^^^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.EXTENSION_CONFLICTING_STATIC_AND_INSTANCE
+  // [cfe] Conflicts with setter 'property2'.
   static void set property3(int x) {}
   //              ^^^^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.EXTENSION_CONFLICTING_STATIC_AND_INSTANCE
+  // [cfe] Conflicts with member 'property3'.
   static int field = 3;
   //         ^^^^^
   // [analyzer] COMPILE_TIME_ERROR.EXTENSION_CONFLICTING_STATIC_AND_INSTANCE
@@ -142,11 +143,11 @@
   //       ^
   // [cfe] 'property' is already declared in this scope.
   void set property2(int value) {}
-  //       ^^^^^^^^^
-  // [cfe] unspecified
+  //       ^
+  // [cfe] Conflicts with member 'property2'.
   int get property3 => 1;
-  //      ^^^^^^^^^
-  // [cfe] unspecified
+  //      ^
+  // [cfe] Conflicts with setter 'property3'.
   void set field(int value) {}
   //       ^
   // [cfe] Conflicts with member 'field'.
@@ -196,10 +197,12 @@
 // Check an instance method colliding with an instance setter.
 extension E10 on int {
   int method() => 0;
+  //  ^
+  // [cfe] Conflicts with setter 'method'.
   void set method(int value) {}
   //       ^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
-  // [cfe] unspecified
+  // [cfe] Conflicts with member 'method'.
 }
 
 // Check a static method colliding with an instance getter.
@@ -217,8 +220,10 @@
   static int method() => 0;
   //         ^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.EXTENSION_CONFLICTING_STATIC_AND_INSTANCE
-  // [cfe] unspecified
+  // [cfe] Conflicts with setter 'method'.
   void set method(int value) {}
+  //       ^
+  // [cfe] Conflicts with member 'method'.
 }
 
 // Check an instance method colliding with a static getter.
@@ -233,10 +238,12 @@
 // Check an instance method colliding with a static setter.
 extension E14 on int {
   int method() => 0;
+  //  ^
+  // [cfe] Conflicts with setter 'method'.
   static void set method(int value) {}
   //              ^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.EXTENSION_CONFLICTING_STATIC_AND_INSTANCE
-  // [cfe] unspecified
+  // [cfe] Conflicts with member 'method'.
 }
 
 // Check an instance method colliding with a static field.
diff --git a/tests/language_2/issue38816_test.dart b/tests/language_2/issue38816_test.dart
new file mode 100644
index 0000000..840e082
--- /dev/null
+++ b/tests/language_2/issue38816_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.
+
+import "package:expect/expect.dart";
+
+void foo<T extends num>(T x) {}
+void bar<T extends num>(num x) {}
+
+typedef F = Function<T extends num>(T x);
+
+void main() {
+  Expect.isTrue(foo is F);
+  Expect.isTrue(bar is F);
+}
diff --git a/tests/language_2/language_2_precompiled.status b/tests/language_2/language_2_precompiled.status
index f89d8f4..d7e999b 100644
--- a/tests/language_2/language_2_precompiled.status
+++ b/tests/language_2/language_2_precompiled.status
@@ -34,9 +34,11 @@
 mixin_mixin_type_arguments_test: Skip
 mixin_super_2_test: Skip
 no_such_method_dispatcher_test: Skip # Uses new Symbol()
-stacktrace_rethrow_error_test: Skip
-stacktrace_rethrow_nonerror_test: Skip
 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_2/subtyping_static/future_or_subtype_test.dart b/tests/language_2/subtyping_static/future_or_subtype_test.dart
new file mode 100644
index 0000000..888ab60
--- /dev/null
+++ b/tests/language_2/subtyping_static/future_or_subtype_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.
+
+import 'dart:async';
+import 'package:expect/expect.dart';
+
+class A implements Future<Future<A>> {
+  @override
+  noSuchMethod(Invocation _) {}
+}
+
+void main() {
+  Expect.notSubtype<A, Future<A>>();
+  Expect.subtype<FutureOr<A>, FutureOr<Future<A>>>();
+}
diff --git a/tests/language_2/variance/variance_in_subclass_error_test.dart b/tests/language_2/variance/variance_in_subclass_error_test.dart
new file mode 100644
index 0000000..7b0db8e
--- /dev/null
+++ b/tests/language_2/variance/variance_in_subclass_error_test.dart
@@ -0,0 +1,123 @@
+// 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 erroneous subclass usage for the `in` variance modifier.
+
+// SharedOptions=--enable-experiment=variance
+
+typedef CovFunction<T> = T Function();
+typedef ContraFunction<T> = void Function(T);
+typedef InvFunction<T> = T Function(T);
+
+class LegacyCovariant<T> {}
+class Covariant<out T> {}
+class Contravariant<in T> {}
+class Invariant<inout T> {}
+mixin MLegacyCovariant<T> {}
+mixin MCovariant<out T> {}
+mixin MContravariant<in T> {}
+mixin MInvariant<inout T> {}
+
+class A<in T> extends LegacyCovariant<T> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'LegacyCovariant'.
+
+class B<in T> implements LegacyCovariant<T> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'LegacyCovariant'.
+
+class C<in T> with MLegacyCovariant<T> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'MLegacyCovariant'.
+
+class D<in T> extends Covariant<T> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
+
+class E<in T> implements Covariant<T> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
+
+class F<in T> with MCovariant<T> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'MCovariant'.
+
+class G<in T> extends Invariant<T> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Invariant'.
+
+class H<in T> implements Invariant<T> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Invariant'.
+
+class I<in T> with MInvariant<T> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'MInvariant'.
+
+class J<in T> extends Covariant<Covariant<T>> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
+
+class K<in T> extends Contravariant<Contravariant<T>> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Contravariant'.
+
+class L<in T> extends Covariant<CovFunction<T>> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
+
+class M<in T> extends Covariant<ContraFunction<ContraFunction<T>>> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
+
+class N<in T> extends Contravariant<CovFunction<Contravariant<T>>> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Contravariant'.
+
+class O<in T> extends Covariant<CovFunction<Covariant<T>>> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
+
+class P<in T> extends Covariant<Covariant<Covariant<T>>> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
+
+class Q<in T> extends Invariant<InvFunction<T>> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Invariant'.
+
+class R<in T> = Covariant<T> with MContravariant<T>;
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
+
+class S<in T> = Contravariant<T> with MCovariant<T>;
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'MCovariant'.
+
+class T<in X> = Invariant<X> with MInvariant<X>;
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'X' in supertype 'Invariant'.
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'X' in supertype 'MInvariant'.
diff --git a/tests/language_2/variance/variance_in_subclass_test.dart b/tests/language_2/variance/variance_in_subclass_test.dart
new file mode 100644
index 0000000..f7a314a
--- /dev/null
+++ b/tests/language_2/variance/variance_in_subclass_test.dart
@@ -0,0 +1,49 @@
+// 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 subclass usage for the `in` variance modifier.
+
+// SharedOptions=--enable-experiment=variance
+
+typedef CovFunction<T> = T Function();
+typedef ContraFunction<T> = void Function(T);
+
+class Covariant<out T> {}
+class Contravariant<in T> {}
+mixin MContravariant<in T> {}
+
+class A<in T> extends Contravariant<T> {}
+class B<in T> implements Contravariant<T> {}
+class C<in T> with MContravariant<T> {}
+
+class D<in T> extends Covariant<Contravariant<T>> {}
+class E<in T> extends Contravariant<Covariant<T>> {}
+
+class F<in T> extends Covariant<ContraFunction<T>> {}
+class G<in T> extends Covariant<ContraFunction<CovFunction<T>>> {}
+class H<in T> extends Covariant<CovFunction<ContraFunction<T>>> {}
+
+class I<in T> extends Covariant<ContraFunction<Covariant<T>>> {}
+
+class J<in T> extends Contravariant<Contravariant<Contravariant<T>>> {}
+
+class K<in T> = Contravariant<T> with MContravariant<T>;
+class L<in T> = Covariant<Contravariant<T>> with MContravariant<T>;
+class M<in T> = Contravariant<T> with MContravariant<Covariant<T>>;
+
+main() {
+  A<num> a = A();
+  B<num> b = B();
+  C<num> c = C();
+  D<num> d = D();
+  E<num> e = E();
+  F<num> f = F();
+  G<num> g = G();
+  H<num> h = H();
+  I<num> i = I();
+  J<num> j = J();
+  K<num> k = K();
+  L<num> l = L();
+  M<num> m = M();
+}
diff --git a/tests/language_2/variance/variance_in_subtyping_error_test.dart b/tests/language_2/variance/variance_in_subtyping_error_test.dart
new file mode 100644
index 0000000..bf51bff
--- /dev/null
+++ b/tests/language_2/variance/variance_in_subtyping_error_test.dart
@@ -0,0 +1,75 @@
+// 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 erroneous subtyping for the `in` variance modifier.
+
+// SharedOptions=--enable-experiment=variance
+
+class Contravariant<in T> {}
+
+class Upper {}
+class Middle extends Upper {}
+class Lower extends Middle {}
+
+class A {
+  Contravariant<Middle> method1() {
+    return new Contravariant<Middle>();
+  }
+
+  void method2(Contravariant<Middle> x) {}
+}
+
+class B extends A {
+  @override
+  Contravariant<Lower> method1() {
+  //                   ^
+  // [analyzer] unspecified
+  // [cfe] The return type of the method 'B.method1' is 'Contravariant<Lower>', which does not match the return type, 'Contravariant<Middle>', of the overridden method, 'A.method1'.
+    return new Contravariant<Lower>();
+  }
+
+  @override
+  void method2(Contravariant<Upper> x) {}
+  //                                ^
+  // [analyzer] unspecified
+  // [cfe] The parameter 'x' of the method 'B.method2' has type 'Contravariant<Upper>', which does not match the corresponding type, 'Contravariant<Middle>', in the overridden method, 'A.method2'.
+}
+
+class C<out T extends Contravariant<Middle>> {}
+
+class D {
+  C<Contravariant<Lower>> method1() {
+  //                             ^
+  // [analyzer] unspecified
+  // [cfe] Type argument 'Contravariant<Lower>' doesn't conform to the bound 'Contravariant<Middle>' of the type variable 'T' on 'C' in the return type.
+    return C<Contravariant<Lower>>();
+    //     ^
+    // [analyzer] unspecified
+    // [cfe] Type argument 'Contravariant<Lower>' doesn't conform to the bound 'Contravariant<Middle>' of the type variable 'T' on 'C'.
+  }
+}
+
+void testCall(Iterable<Contravariant<Middle>> x) {}
+
+main() {
+  C<Contravariant<Lower>> c = new C<Contravariant<Lower>>();
+  //                      ^
+  // [analyzer] unspecified
+  // [cfe] Type argument 'Contravariant<Lower>' doesn't conform to the bound 'Contravariant<Middle>' of the type variable 'T' on 'C'.
+  //                              ^
+  // [analyzer] unspecified
+  // [cfe] Type argument 'Contravariant<Lower>' doesn't conform to the bound 'Contravariant<Middle>' of the type variable 'T' on 'C'.
+
+  Iterable<Contravariant<Middle>> iterableMiddle = [new Contravariant<Middle>()];
+  List<Contravariant<Lower>> listLower = [new Contravariant<Lower>()];
+  iterableMiddle = listLower;
+  //               ^
+  // [analyzer] unspecified
+  // [cfe] A value of type 'List<Contravariant<Lower>>' can't be assigned to a variable of type 'Iterable<Contravariant<Middle>>'.
+
+  testCall(listLower);
+  //       ^
+  // [analyzer] unspecified
+  // [cfe] The argument type 'List<Contravariant<Lower>>' can't be assigned to the parameter type 'Iterable<Contravariant<Middle>>'.
+}
diff --git a/tests/language_2/variance/variance_in_subtyping_test.dart b/tests/language_2/variance/variance_in_subtyping_test.dart
new file mode 100644
index 0000000..c44d77e
--- /dev/null
+++ b/tests/language_2/variance/variance_in_subtyping_test.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.
+
+// Tests subtyping for the `in` variance modifier.
+
+// SharedOptions=--enable-experiment=variance
+
+class Contravariant<in T> {}
+
+class Upper {}
+class Middle extends Upper {}
+class Lower extends Middle {}
+
+class A {
+  Contravariant<Middle> method1() {
+    return Contravariant<Middle>();
+  }
+
+  void method2(Contravariant<Middle> x) {}
+}
+
+class B extends A {
+  @override
+  Contravariant<Upper> method1() {
+    return new Contravariant<Upper>();
+  }
+
+  @override
+  void method2(Contravariant<Lower> x) {}
+}
+
+class C extends A {
+  @override
+  Contravariant<Middle> method1() {
+    return new Contravariant<Middle>();
+  }
+
+  @override
+  void method2(Contravariant<Middle> x) {}
+}
+
+class D<out T extends Contravariant<Middle>> {}
+
+class E {
+  D<Contravariant<Upper>> method1() {
+    return D<Contravariant<Upper>>();
+  }
+}
+
+class F {
+  D<Contravariant<Middle>> method1() {
+    return D<Contravariant<Middle>>();
+  }
+}
+
+void testCall(Iterable<Contravariant<Lower>> x) {}
+
+main() {
+  A a = new A();
+  a.method2(new Contravariant<Middle>());
+  a.method2(new Contravariant<Upper>());
+
+  B b = new B();
+  b.method2(new Contravariant<Lower>());
+  b.method2(new Contravariant<Middle>());
+
+  C c = new C();
+  c.method2(new Contravariant<Middle>());
+  c.method2(new Contravariant<Upper>());
+
+  D<Contravariant<Upper>> dUpper = new D<Contravariant<Upper>>();
+  D<Contravariant<Middle>> dMiddle = new D<Contravariant<Middle>>();
+
+  E e = new E();
+
+  F f = new F();
+
+  Iterable<Contravariant<Lower>> iterableLower = [new Contravariant<Lower>()];
+  List<Contravariant<Middle>> listMiddle = [new Contravariant<Middle>()];
+  iterableLower = listMiddle;
+
+  testCall(listMiddle);
+}
diff --git a/tests/language_2/variance/variance_inout_subclass_test.dart b/tests/language_2/variance/variance_inout_subclass_test.dart
new file mode 100644
index 0000000..e1b7122c
--- /dev/null
+++ b/tests/language_2/variance/variance_inout_subclass_test.dart
@@ -0,0 +1,90 @@
+// 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 subclass usage for the `inout` variance modifier.
+
+// SharedOptions=--enable-experiment=variance
+
+typedef CovFunction<T> = T Function();
+typedef ContraFunction<T> = void Function(T);
+typedef InvFunction<T> = T Function(T);
+
+class LegacyCovariant<T> {}
+class Invariant<inout T>{}
+class Covariant<out T> {}
+class Contravariant<in T> {}
+mixin MLegacyCovariant<T> {}
+mixin MContravariant<in T> {}
+mixin MCovariant<out T> {}
+mixin MInvariant<inout T> {}
+
+class A<inout T> extends LegacyCovariant<T> {}
+class B<inout T> extends Invariant<T> {}
+class C<inout T> extends Covariant<T> {}
+class D<inout T> extends Contravariant<T> {}
+
+class E<inout T> implements LegacyCovariant<T> {}
+class F<inout T> implements Invariant<T> {}
+class G<inout T> implements Covariant<T> {}
+class H<inout T> implements Contravariant<T> {}
+
+class I<inout T> with MLegacyCovariant<T> {}
+class J<inout T> with MInvariant<T> {}
+class K<inout T> with MCovariant<T> {}
+class L<inout T> with MContravariant<T> {}
+
+class M<inout T> extends Covariant<Contravariant<T>> {}
+class N<inout T> extends Contravariant<Covariant<T>> {}
+class O<inout T> extends Covariant<ContraFunction<T>> {}
+class P<inout T> extends Covariant<ContraFunction<CovFunction<T>>> {}
+class Q<inout T> extends Covariant<CovFunction<ContraFunction<T>>> {}
+class R<inout T> extends Covariant<ContraFunction<Covariant<T>>> {}
+class S<inout T> extends Contravariant<Contravariant<Contravariant<T>>> {}
+
+class T<inout X> extends Covariant<Covariant<X>> {}
+class U<inout T> extends Contravariant<Contravariant<T>> {}
+class V<inout T> extends Covariant<CovFunction<T>> {}
+class W<inout T> extends Covariant<ContraFunction<ContraFunction<T>>> {}
+class X<inout T> extends Contravariant<CovFunction<Contravariant<T>>> {}
+class Y<inout T> extends Covariant<CovFunction<Covariant<T>>> {}
+class Z<inout T> extends Covariant<Covariant<Covariant<T>>> {}
+
+class AA<inout T> extends Covariant<InvFunction<T>> {}
+
+class AB<inout T> = Invariant<T> with MInvariant<T>;
+class AC<inout T> = Covariant<T> with MCovariant<T>;
+class AD<inout T> = Contravariant<T> with MContravariant<T>;
+
+main() {
+  A<num> a = A();
+  B<num> b = B();
+  C<num> c = C();
+  D<num> d = D();
+  E<num> e = E();
+  F<num> f = F();
+  G<num> g = G();
+  H<num> h = H();
+  I<num> i = I();
+  J<num> j = J();
+  K<num> k = K();
+  L<num> l = L();
+  M<num> m = M();
+  N<num> n = N();
+  O<num> o = O();
+  P<num> p = P();
+  Q<num> q = Q();
+  R<num> r = R();
+  S<num> s = S();
+  T<num> t = T();
+  U<num> u = U();
+  V<num> v = V();
+  W<num> w = W();
+  X<num> x = X();
+  Y<num> y = Y();
+  Z<num> z = Z();
+  AA<num> aa = AA();
+  AB<num> ab = AB();
+  AC<num> ac = AC();
+  AD<num> ad = AD();
+}
diff --git a/tests/language_2/variance/variance_inout_subtyping_error_test.dart b/tests/language_2/variance/variance_inout_subtyping_error_test.dart
new file mode 100644
index 0000000..0ca248a
--- /dev/null
+++ b/tests/language_2/variance/variance_inout_subtyping_error_test.dart
@@ -0,0 +1,125 @@
+// 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 erroneous subtyping for the `inout` variance modifier.
+
+// SharedOptions=--enable-experiment=variance
+
+class Invariant<inout T> {}
+
+class Upper {}
+class Middle extends Upper {}
+class Lower extends Middle {}
+
+class A {
+  Invariant<Middle> method1() {
+    return Invariant<Middle>();
+  }
+
+  void method2(Invariant<Middle> x) {}
+}
+
+class B extends A {
+  @override
+  Invariant<Upper> method1() {
+  //               ^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.INVALID_OVERRIDE
+  // [cfe] The return type of the method 'B.method1' is 'Invariant<Upper>', which does not match the return type, 'Invariant<Middle>', of the overridden method, 'A.method1'.
+    return new Invariant<Upper>();
+  }
+
+  @override
+  void method2(Invariant<Lower> x) {}
+  //   ^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.INVALID_OVERRIDE
+  //                            ^
+  // [cfe] The parameter 'x' of the method 'B.method2' has type 'Invariant<Lower>', which does not match the corresponding type, 'Invariant<Middle>', in the overridden method, 'A.method2'.
+}
+
+class C extends A {
+  @override
+  Invariant<Lower> method1() {
+  //               ^
+  // [analyzer] unspecified
+  // [cfe] The return type of the method 'C.method1' is 'Invariant<Lower>', which does not match the return type, 'Invariant<Middle>', of the overridden method, 'A.method1'.
+    return new Invariant<Lower>();
+  }
+
+  @override
+  void method2(Invariant<Upper> x) {}
+  //                            ^
+  // [analyzer] unspecified
+  // [cfe] The parameter 'x' of the method 'C.method2' has type 'Invariant<Upper>', which does not match the corresponding type, 'Invariant<Middle>', in the overridden method, 'A.method2'.
+}
+
+class D<out T extends Invariant<Middle>> {}
+
+class E {
+  D<Invariant<Upper>> method1() {
+  //^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS
+  //                         ^
+  // [cfe] Type argument 'Invariant<Upper>' doesn't conform to the bound 'Invariant<Middle>' of the type variable 'T' on 'D' in the return type.
+    return D<Invariant<Upper>>();
+    //     ^
+    // [cfe] Type argument 'Invariant<Upper>' doesn't conform to the bound 'Invariant<Middle>' of the type variable 'T' on 'D'.
+    //       ^^^^^^^^^^^^^^^^
+    // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS
+  }
+
+  D<Invariant<Lower>> method2() {
+  //                         ^
+  // [analyzer] unspecified
+  // [cfe] Type argument 'Invariant<Lower>' doesn't conform to the bound 'Invariant<Middle>' of the type variable 'T' on 'D' in the return type.
+    return D<Invariant<Lower>>();
+    //     ^
+    // [analyzer] unspecified
+    // [cfe] Type argument 'Invariant<Lower>' doesn't conform to the bound 'Invariant<Middle>' of the type variable 'T' on 'D'.
+  }
+}
+
+void testCall<T>(Iterable<Invariant<T>> x) {}
+
+main() {
+  D<Invariant<Upper>> dUpper = new D<Invariant<Upper>>();
+  //^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS
+  //                  ^
+  // [cfe] Type argument 'Invariant<Upper>' doesn't conform to the bound 'Invariant<Middle>' of the type variable 'T' on 'D'.
+  //                               ^
+  // [cfe] Type argument 'Invariant<Upper>' doesn't conform to the bound 'Invariant<Middle>' of the type variable 'T' on 'D'.
+  //                                 ^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS
+  D<Invariant<Lower>> dLower = new D<Invariant<Lower>>();
+  //                  ^
+  // [analyzer] unspecified
+  // [cfe] Type argument 'Invariant<Lower>' doesn't conform to the bound 'Invariant<Middle>' of the type variable 'T' on 'D'.
+  //                               ^
+  // [analyzer] unspecified
+  // [cfe] Type argument 'Invariant<Lower>' doesn't conform to the bound 'Invariant<Middle>' of the type variable 'T' on 'D'.
+
+  Iterable<Invariant<Lower>> iterableLower = [new Invariant<Lower>()];
+  List<Invariant<Middle>> listMiddle = [new Invariant<Middle>()];
+  iterableLower = listMiddle;
+  //              ^^^^^^^^^^
+  // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
+  // [cfe] A value of type 'List<Invariant<Middle>>' can't be assigned to a variable of type 'Iterable<Invariant<Lower>>'.
+
+  Iterable<Invariant<Middle>> iterableMiddle = [new Invariant<Middle>()];
+  List<Invariant<Lower>> listLower = [new Invariant<Lower>()];
+  iterableMiddle = listLower;
+  //               ^
+  // [analyzer] unspecified
+  // [cfe] A value of type 'List<Invariant<Lower>>' can't be assigned to a variable of type 'Iterable<Invariant<Middle>>'.
+
+  testCall<Lower>(listMiddle);
+  //              ^^^^^^^^^^
+  // [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  // [cfe] The argument type 'List<Invariant<Middle>>' can't be assigned to the parameter type 'Iterable<Invariant<Lower>>'.
+
+  testCall<Middle>(listLower);
+  //               ^
+  // [analyzer] unspecified
+  // [cfe] The argument type 'List<Invariant<Lower>>' can't be assigned to the parameter type 'Iterable<Invariant<Middle>>'.
+}
diff --git a/tests/language_2/variance/variance_inout_subtyping_test.dart b/tests/language_2/variance/variance_inout_subtyping_test.dart
new file mode 100644
index 0000000..9ebdea5
--- /dev/null
+++ b/tests/language_2/variance/variance_inout_subtyping_test.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.
+
+// Tests subtyping for the `inout` variance modifier.
+
+// SharedOptions=--enable-experiment=variance
+
+class Invariant<inout T> {}
+
+class Upper {}
+class Middle extends Upper {}
+class Lower extends Middle {}
+
+class A {
+  Invariant<Middle> method1() {
+    return new Invariant<Middle>();
+  }
+
+  void method2(Invariant<Middle> x) {}
+}
+
+class B extends A {
+  @override
+  Invariant<Middle> method1() {
+    return new Invariant<Middle>();
+  }
+
+  @override
+  void method2(Invariant<Middle> x) {}
+}
+
+class C<out X extends Invariant<Middle>> {}
+
+class D {
+  C<Invariant<Middle>> method1() {
+    return C<Invariant<Middle>>();
+  }
+}
+
+void testCall(Iterable<Invariant<Middle>> x) {}
+
+main() {
+  A a = new A();
+  a.method2(new Invariant<Middle>());
+
+  B b = new B();
+  b.method2(new Invariant<Middle>());
+
+  C<Invariant<Middle>> c = new C<Invariant<Middle>>();
+
+  D d = new D();
+
+  Iterable<Invariant<Middle>> iterableMiddle = [new Invariant<Middle>()];
+  List<Invariant<Middle>> listMiddle = [new Invariant<Middle>()];
+  iterableMiddle = listMiddle;
+
+  testCall(listMiddle);
+}
diff --git a/tests/language_2/variance/variance_multi_subclass_error_test.dart b/tests/language_2/variance/variance_multi_subclass_error_test.dart
new file mode 100644
index 0000000..358c81f
--- /dev/null
+++ b/tests/language_2/variance/variance_multi_subclass_error_test.dart
@@ -0,0 +1,71 @@
+// 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 erroneous variance usage multiple type parameters.
+
+// SharedOptions=--enable-experiment=variance
+
+typedef CovFunction<T> = T Function();
+typedef ContraFunction<T> = void Function(T);
+
+class Covariant<out T> {}
+class Contravariant<in T> {}
+
+class MultiTwo<in T, out U> {}
+class MultiThree<in T, out U, inout V> {}
+
+class A<in T, out U, inout V> extends Covariant<T> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
+
+class B<in T> extends MultiThree<T, T, T> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'MultiThree'.
+
+class C<in T, out U, inout V> extends MultiTwo<U, T> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'MultiTwo'.
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'U' in supertype 'MultiTwo'.
+
+class D<in T, out U, inout V> extends MultiThree<V, U, T> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'MultiThree'.
+
+class E<in T, out U, inout V> extends MultiThree<Covariant<U>, Covariant<T>, Covariant<U>> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'MultiThree'.
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'U' in supertype 'MultiThree'.
+
+class F<in T, out U, inout V> extends MultiTwo<Contravariant<T>, Contravariant<U>> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'MultiTwo'.
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'U' in supertype 'MultiTwo'.
+
+class G<in T, out U, inout V> extends MultiThree<CovFunction<U>, CovFunction<T>, CovFunction<U>> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'MultiThree'.
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'U' in supertype 'MultiThree'.
+
+class H<in T, out U, inout V> extends MultiTwo<ContraFunction<T>, ContraFunction<U>> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'MultiTwo'.
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'U' in supertype 'MultiTwo'.
diff --git a/tests/language_2/variance/variance_multi_subclass_test.dart b/tests/language_2/variance/variance_multi_subclass_test.dart
new file mode 100644
index 0000000..ae4f57a
--- /dev/null
+++ b/tests/language_2/variance/variance_multi_subclass_test.dart
@@ -0,0 +1,42 @@
+// 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 variance usage multiple type parameters.
+
+// SharedOptions=--enable-experiment=variance
+
+typedef CovFunction<T> = T Function();
+typedef ContraFunction<T> = void Function(T);
+
+class Covariant<out T> {}
+class Contravariant<in T> {}
+
+class A<in T, out U> {}
+class B<in T, out U, inout V> {}
+
+class C<inout T, in U, out V> extends A<T, V> {}
+class D<inout T, in U, out V> extends B<U, V, T> {}
+class E<inout T, in U, out V> extends B<T, T, T> {}
+
+class F<inout T, in U, out V> extends A<Contravariant<V>, Contravariant<U>> {}
+class G<inout T, in U, out V> extends A<Covariant<Contravariant<V>>, Contravariant<Covariant<U>>> {}
+class H<inout T, in U, out V> extends B<Covariant<U>, Covariant<V>, Covariant<T>> {}
+
+class I<inout T, in U, out V> extends A<ContraFunction<V>, ContraFunction<U>> {}
+class J<inout T, in U, out V> extends A<CovFunction<ContraFunction<V>>, ContraFunction<CovFunction<U>>> {}
+class K<inout T, in U, out V> extends B<CovFunction<U>, CovFunction<V>, CovFunction<T>> {}
+
+main() {
+  A<num, bool> a = A();
+  B<num, bool, String> b = B();
+  C<num, bool, String> c = C();
+  D<num, bool, String> d = D();
+  E<num, bool, String> e = E();
+  F<num, bool, String> f = F();
+  G<num, bool, String> g = G();
+  H<num, bool, String> h = H();
+  I<num, bool, String> i = I();
+  J<num, bool, String> j = J();
+  K<num, bool, String> k = K();
+}
diff --git a/tests/language_2/variance/variance_out_subclass_error_test.dart b/tests/language_2/variance/variance_out_subclass_error_test.dart
new file mode 100644
index 0000000..24eb2b8
--- /dev/null
+++ b/tests/language_2/variance/variance_out_subclass_error_test.dart
@@ -0,0 +1,106 @@
+// 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 erroneous subclass usage for the `out` variance modifier.
+
+// SharedOptions=--enable-experiment=variance
+
+typedef CovFunction<T> = T Function();
+typedef ContraFunction<T> = void Function(T);
+typedef InvFunction<T> = T Function(T);
+
+class Covariant<out T> {}
+class Contravariant<in T> {}
+class Invariant<inout T> {}
+mixin MCovariant<out T> {}
+mixin MContravariant<in T> {}
+mixin MInvariant<in T> {}
+
+class A<out T> extends Contravariant<T> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Contravariant'.
+
+class B<out T> implements Contravariant<T> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Contravariant'.
+
+class C<out T> with MContravariant<T> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'MContravariant'.
+
+class D<out T> extends Invariant<T> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Invariant'.
+
+class E<out T> implements Invariant<T> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Invariant'.
+
+class F<out T> with MInvariant<T> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'MInvariant'.
+
+class G<out T> extends Covariant<Contravariant<T>> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
+
+class H<out T> extends Contravariant<Covariant<T>> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Contravariant'.
+
+class I<out T> extends Covariant<ContraFunction<T>> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
+
+class J<out T> extends Covariant<ContraFunction<CovFunction<T>>> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
+
+class K<out T> extends Covariant<CovFunction<ContraFunction<T>>> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
+
+class L<out T> extends Covariant<ContraFunction<Covariant<T>>> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
+
+class M<out T> extends Contravariant<Contravariant<Contravariant<T>>> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Contravariant'.
+
+class N<out T> extends Covariant<InvFunction<T>> {}
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Covariant'.
+
+class O<out T> = Covariant<T> with MContravariant<T>;
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'MContravariant'.
+
+class P<out T> = Contravariant<T> with MCovariant<T>;
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Contravariant'.
+
+class Q<out T> = Invariant<T> with MInvariant<T>;
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'Invariant'.
+//    ^
+// [analyzer] unspecified
+// [cfe] Found unsupported uses of 'T' in supertype 'MInvariant'.
diff --git a/tests/language_2/variance/variance_out_subclass_test.dart b/tests/language_2/variance/variance_out_subclass_test.dart
new file mode 100644
index 0000000..0c8861d
--- /dev/null
+++ b/tests/language_2/variance/variance_out_subclass_test.dart
@@ -0,0 +1,58 @@
+// 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 subclass usage for the `out` variance modifier.
+
+// SharedOptions=--enable-experiment=variance
+
+typedef CovFunction<T> = T Function();
+typedef ContraFunction<T> = void Function(T);
+
+class LegacyCovariant<T> {}
+class Covariant<out T> {}
+class Contravariant<in T> {}
+mixin MLegacyCovariant<T> {}
+mixin MCovariant<out T> {}
+
+class A<out T> extends LegacyCovariant<T> {}
+class B<out T> implements LegacyCovariant<T> {}
+class C<out T> with MLegacyCovariant<T> {}
+
+class D<out T> extends Covariant<T> {}
+class E<out T> implements Covariant<T> {}
+class F<out T> with MCovariant<T> {}
+
+class G<out T> extends Covariant<Covariant<T>> {}
+class H<out T> extends Contravariant<Contravariant<T>> {}
+
+class I<out T> extends Covariant<CovFunction<T>> {}
+class J<out T> extends Covariant<ContraFunction<ContraFunction<T>>> {}
+class K<out T> extends Contravariant<CovFunction<Contravariant<T>>> {}
+
+class L<out T> extends Covariant<CovFunction<Covariant<T>>> {}
+
+class M<out T> extends Covariant<Covariant<Covariant<T>>> {}
+
+class N<out T> = Covariant<T> with MCovariant<T>;
+class O<out T> = Contravariant<Contravariant<T>> with MCovariant<T>;
+class P<out T> = Covariant<T> with MCovariant<Covariant<T>>;
+
+main() {
+  A<num> a = A();
+  B<num> b = B();
+  C<num> c = C();
+  D<num> d = D();
+  E<num> e = E();
+  F<num> f = F();
+  G<num> g = G();
+  H<num> h = H();
+  I<num> i = I();
+  J<num> j = J();
+  K<num> k = K();
+  L<num> l = L();
+  M<num> m = M();
+  N<num> n = N();
+  O<num> o = O();
+  P<num> p = P();
+}
diff --git a/tests/language_2/variance/variance_out_subtyping_error_test.dart b/tests/language_2/variance/variance_out_subtyping_error_test.dart
new file mode 100644
index 0000000..a85f4cb
--- /dev/null
+++ b/tests/language_2/variance/variance_out_subtyping_error_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.
+
+// Tests erroneous subtyping for the `out` variance modifier.
+
+// SharedOptions=--enable-experiment=variance
+
+class Covariant<out T> {}
+
+class Upper {}
+class Middle extends Upper {}
+class Lower {}
+
+class A {
+  Covariant<Middle> method1() {
+    return Covariant<Middle>();
+  }
+
+  void method2(Covariant<Middle> x) {}
+}
+
+class B extends A {
+  @override
+  Covariant<Upper> method1() {
+  //               ^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.INVALID_OVERRIDE
+  // [cfe] The return type of the method 'B.method1' is 'Covariant<Upper>', which does not match the return type, 'Covariant<Middle>', of the overridden method, 'A.method1'.
+    return new Covariant<Upper>();
+  }
+
+  @override
+  void method2(Covariant<Lower> x) {}
+  //   ^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.INVALID_OVERRIDE
+  //                            ^
+  // [cfe] The parameter 'x' of the method 'B.method2' has type 'Covariant<Lower>', which does not match the corresponding type, 'Covariant<Middle>', in the overridden method, 'A.method2'.
+}
+
+class C<out T extends Covariant<Middle>> {}
+
+class D {
+  C<Covariant<Upper>> method1() {
+  //^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS
+  //                         ^
+  // [cfe] Type argument 'Covariant<Upper>' doesn't conform to the bound 'Covariant<Middle>' of the type variable 'T' on 'C' in the return type.
+    return C<Covariant<Upper>>();
+    //     ^
+    // [cfe] Type argument 'Covariant<Upper>' doesn't conform to the bound 'Covariant<Middle>' of the type variable 'T' on 'C'.
+    //       ^^^^^^^^^^^^^^^^
+    // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS
+  }
+}
+
+void testCall(Iterable<Covariant<Lower>> x) {}
+
+main() {
+  C<Covariant<Upper>> c = new C<Covariant<Upper>>();
+  //^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS
+  //                  ^
+  // [cfe] Type argument 'Covariant<Upper>' doesn't conform to the bound 'Covariant<Middle>' of the type variable 'T' on 'C'.
+  //                          ^
+  // [cfe] Type argument 'Covariant<Upper>' doesn't conform to the bound 'Covariant<Middle>' of the type variable 'T' on 'C'.
+  //                            ^^^^^^^^^^^^^^^^
+  // [analyzer] COMPILE_TIME_ERROR.TYPE_ARGUMENT_NOT_MATCHING_BOUNDS
+
+  Iterable<Covariant<Lower>> iterableLower = [new Covariant<Lower>()];
+  List<Covariant<Middle>> listMiddle = [new Covariant<Middle>()];
+  iterableLower = listMiddle;
+  //              ^^^^^^^^^^
+  // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
+  // [cfe] A value of type 'List<Covariant<Middle>>' can't be assigned to a variable of type 'Iterable<Covariant<Lower>>'.
+
+  testCall(listMiddle);
+  //       ^^^^^^^^^^
+  // [analyzer] STATIC_WARNING.ARGUMENT_TYPE_NOT_ASSIGNABLE
+  // [cfe] The argument type 'List<Covariant<Middle>>' can't be assigned to the parameter type 'Iterable<Covariant<Lower>>'.
+}
diff --git a/tests/language_2/variance/variance_out_subtyping_test.dart b/tests/language_2/variance/variance_out_subtyping_test.dart
new file mode 100644
index 0000000..a057a05
--- /dev/null
+++ b/tests/language_2/variance/variance_out_subtyping_test.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.
+
+// Tests subtyping for the `out` variance modifier.
+
+// SharedOptions=--enable-experiment=variance
+
+class Covariant<out T> {}
+
+class Upper {}
+class Middle extends Upper {}
+class Lower extends Middle {}
+
+class A {
+  Covariant<Middle> method1() {
+    return new Covariant<Middle>();
+  }
+
+  void method2(Covariant<Middle> x) {}
+}
+
+class B extends A {
+  @override
+  Covariant<Lower> method1() {
+    return new Covariant<Lower>();
+  }
+
+  @override
+  void method2(Covariant<Upper> x) {}
+}
+
+class C extends A {
+  @override
+  Covariant<Middle> method1() {
+    return new Covariant<Middle>();
+  }
+
+  @override
+  void method2(Covariant<Middle> x) {}
+}
+
+class D<out T extends Covariant<Middle>> {}
+
+class E {
+  D<Covariant<Lower>> method1() {
+    return D<Covariant<Lower>>();
+  }
+}
+
+class F {
+  D<Covariant<Middle>> method1() {
+    return D<Covariant<Middle>>();
+  }
+}
+
+void testCall(Iterable<Covariant<Middle>> x) {}
+
+main() {
+  A a = new A();
+  a.method2(new Covariant<Middle>());
+  a.method2(new Covariant<Lower>());
+
+  B b = new B();
+  b.method2(new Covariant<Upper>());
+  b.method2(new Covariant<Middle>());
+
+  C c = new C();
+  c.method2(new Covariant<Middle>());
+  c.method2(new Covariant<Lower>());
+
+  D<Covariant<Lower>> dLower = new D<Covariant<Lower>>();
+  D<Covariant<Middle>> dMiddle = new D<Covariant<Middle>>();
+
+  E e = new E();
+
+  F f = new F();
+
+  Iterable<Covariant<Middle>> iterableMiddle = [new Covariant<Middle>()];
+  List<Covariant<Lower>> listLower = [new Covariant<Lower>()];
+  iterableMiddle = listLower;
+
+  testCall(listLower);
+}
diff --git a/tests/language_2/vm/regression_38741.dart b/tests/language_2/vm/regression_38741.dart
new file mode 100644
index 0000000..2dd1223
--- /dev/null
+++ b/tests/language_2/vm/regression_38741.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.
+
+// VMOptions=--deterministic
+
+// Found by DartFuzzing: would fail during deopt:
+// https://github.com/dart-lang/sdk/issues/38741
+
+import 'package:expect/expect.dart';
+
+@pragma('vm:prefer-inline')
+bool foo(int x) => x < 10;
+
+@pragma('vm:never-inline')
+bool bar(bool f) => f && foo(1);
+
+void main() {
+  try {
+    foo(null); // seed feedback for x < 10 with null receiver cid
+  } catch (e) {}
+  // Now when foo will be inlined into bar we will know that x is Smi,
+  // this hower disagrees with type feedback (which currently is monomorphic and
+  // expects null receiver for x < 10).
+  for (var i = 0; i < 10000; i++) Expect.isFalse(bar(false));
+  Expect.isTrue(bar(true));
+}
diff --git a/tests/lib_2/mirrors/method_mirror_extension_test.dart b/tests/lib_2/mirrors/method_mirror_extension_test.dart
new file mode 100644
index 0000000..2d68474
--- /dev/null
+++ b/tests/lib_2/mirrors/method_mirror_extension_test.dart
@@ -0,0 +1,126 @@
+// 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=extension-methods
+
+library lib;
+
+import "dart:mirrors";
+
+import "package:expect/expect.dart";
+
+class C<T> {
+  static int tracefunc() {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      print(s);
+    }
+    return 10;
+  }
+}
+
+extension ext<T> on C<T> {
+  func() {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      print(s);
+    }
+  }
+
+  get prop {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      print(s);
+    }
+  }
+
+  set prop(value) {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      print(s);
+    }
+  }
+
+  operator +(val) {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      print(s);
+    }
+  }
+
+  operator -(val) {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      print(s);
+    }
+  }
+
+  static int sfld = C.tracefunc();
+  static sfunc() {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      print(s);
+    }
+  }
+
+  static get sprop {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      print(s);
+    }
+  }
+
+  static set sprop(value) {
+    try {
+      throw "producing a stack trace";
+    } catch (e, s) {
+      print(s);
+    }
+  }
+}
+
+checkExtensionKind(closure, kind, name) {
+  var closureMirror = reflect(closure) as ClosureMirror;
+  var methodMirror = closureMirror.function;
+  Expect.isTrue(methodMirror.simpleName.toString().contains(name));
+  Expect.equals(kind, methodMirror.isExtensionMember, "isExtension");
+}
+
+void testExtension(sym, mirror) {
+  if (mirror is MethodMirror) {
+    var methodMirror = mirror as MethodMirror;
+    if (MirrorSystem.getName(sym).startsWith('ext', 0)) {
+      Expect.equals(true, methodMirror.isExtensionMember, "isExtension");
+      Expect.isTrue(methodMirror.simpleName.toString().contains('ext.'));
+    } else {
+      Expect.equals(false, methodMirror.isExtensionMember, "isExtension");
+    }
+  } else if (mirror is VariableMirror) {
+    var variableMirror = mirror as VariableMirror;
+    if (MirrorSystem.getName(sym).startsWith('ext', 0)) {
+      Expect.equals(true, variableMirror.isExtensionMember, "isExtension");
+    } else {
+      Expect.equals(false, variableMirror.isExtensionMember, "isExtension");
+    }
+  }
+}
+
+main() {
+  checkExtensionKind(C.tracefunc, false, 'tracefunc');
+
+  C c = new C();
+  checkExtensionKind(c.func, true, 'ext.func');
+  checkExtensionKind(ext.sfunc, true, 'ext.sfunc');
+
+  var libraryMirror = reflectClass(C).owner as LibraryMirror;
+  libraryMirror.declarations.forEach(testExtension);
+}
diff --git a/tests/lib_2/mirrors/method_mirror_properties_test.dart b/tests/lib_2/mirrors/method_mirror_properties_test.dart
index ef1212f..ece78ed 100644
--- a/tests/lib_2/mirrors/method_mirror_properties_test.dart
+++ b/tests/lib_2/mirrors/method_mirror_properties_test.dart
@@ -43,6 +43,7 @@
   Expect.equals(kinds[2], method.isGetter, "isGetter");
   Expect.equals(kinds[3], method.isSetter, "isSetter");
   Expect.equals(kinds[4], method.isConstructor, "isConstructor");
+  Expect.equals(false, method.isExtensionMember, "isExtension");
 }
 
 main() {
diff --git a/tests/modular/extension_methods/def2.dart b/tests/modular/extension_methods/def2.dart
new file mode 100644
index 0000000..2740389
--- /dev/null
+++ b/tests/modular/extension_methods/def2.dart
@@ -0,0 +1,5 @@
+// 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.
+
+export 'def.dart';
diff --git a/tests/modular/extension_methods/main.dart b/tests/modular/extension_methods/main.dart
index cb18018..9e71195 100644
--- a/tests/modular/extension_methods/main.dart
+++ b/tests/modular/extension_methods/main.dart
@@ -4,7 +4,7 @@
 
 import 'package:expect/expect.dart';
 
-import 'def.dart';
+import 'def2.dart';
 
 main() {
   testExplicitAccess(new Class(42));
diff --git a/tests/modular/extension_methods/modules.yaml b/tests/modular/extension_methods/modules.yaml
index 854c44f..f58c895 100644
--- a/tests/modular/extension_methods/modules.yaml
+++ b/tests/modular/extension_methods/modules.yaml
@@ -3,6 +3,7 @@
 # BSD-style license that can be found in the LICENSE file.
 #
 dependencies:
-  main: [def, expect]
+  def2: [def]
+  main: [def2, expect]
 flags: 
   - extension-methods
\ No newline at end of file
diff --git a/tests/standalone_2/dwarf_stack_trace_test.dart b/tests/standalone_2/dwarf_stack_trace_test.dart
index 32a80bb..410360f 100644
--- a/tests/standalone_2/dwarf_stack_trace_test.dart
+++ b/tests/standalone_2/dwarf_stack_trace_test.dart
@@ -66,8 +66,8 @@
     throw "'file' failed";
     return;
   }
-  if (!result.stdout.contains("Mach-O")) {
-    print("Skipping test because we are not running from a dylib");
+  if (!result.stdout.contains("ELF") && !result.stdout.contains("Mach-O")) {
+    print("Skipping test because we are not running from a dylib or ELF.");
     return;
   }
 
diff --git a/tests/standalone_2/io/file_error2_test.dart b/tests/standalone_2/io/file_error2_test.dart
index 6e21417..e8751c8 100644
--- a/tests/standalone_2/io/file_error2_test.dart
+++ b/tests/standalone_2/io/file_error2_test.dart
@@ -7,6 +7,7 @@
 // Customize ASAN options for this test with 'allocator_may_return_null=1' as
 // it tries to allocate a large memory buffer.
 // Environment=ASAN_OPTIONS=handle_segv=0:detect_stack_use_after_return=1:allocator_may_return_null=1
+// Environment=LSAN_OPTIONS=handle_segv=0:detect_stack_use_after_return=1:allocator_may_return_null=1
 // Environment=MSAN_OPTIONS=handle_segv=0:detect_stack_use_after_return=1:allocator_may_return_null=1
 
 import "dart:io";
diff --git a/tests/standalone_2/io/file_system_watcher_test.dart b/tests/standalone_2/io/file_system_watcher_test.dart
index 14eb5f9..c7c3644 100644
--- a/tests/standalone_2/io/file_system_watcher_test.dart
+++ b/tests/standalone_2/io/file_system_watcher_test.dart
@@ -352,9 +352,14 @@
   });
 
   Completer<bool> workerExitedCompleter = Completer();
-  RawReceivePort exitReceivePort = RawReceivePort((object) { workerExitedCompleter.complete(true); });
-  RawReceivePort errorReceivePort = RawReceivePort((object) { print('worker errored: $object'); });
-  await Isolate.spawn(modifyFiles, receivePort.sendPort, onExit: exitReceivePort.sendPort, onError: errorReceivePort.sendPort);
+  RawReceivePort exitReceivePort = RawReceivePort((object) {
+    workerExitedCompleter.complete(true);
+  });
+  RawReceivePort errorReceivePort = RawReceivePort((object) {
+    print('worker errored: $object');
+  });
+  Isolate isolate = await Isolate.spawn(modifyFiles, receivePort.sendPort,
+      onExit: exitReceivePort.sendPort, onError: errorReceivePort.sendPort);
 
   await modificationEventReceived.future;
   workerSendPort.send('end');
@@ -363,6 +368,8 @@
   await workerExitedCompleter.future;
   exitReceivePort.close();
   errorReceivePort.close();
+  // Stop modifier isolate
+  isolate.kill();
   asyncEnd();
 }
 
@@ -384,7 +391,7 @@
   });
   sendPort.send([receivePort.sendPort, dir.path]);
   bool notificationSent = false;
-  while(!done) {
+  while (!done) {
     // Start modifying the file continuously before watcher start watching.
     for (int i = 0; i < 100; i++) {
       file.writeAsStringSync('a');
@@ -400,6 +407,57 @@
   sendPort.send('end');
 }
 
+testWatchOverflow() async {
+  // When underlying buffer for ReadDirectoryChangesW overflows(on Windows),
+  // it will send an exception to Stream which has been listened.
+  // Bug: https://github.com/dart-lang/sdk/issues/37233
+  asyncStart();
+  ReceivePort receivePort = ReceivePort();
+  Completer<bool> exiting = Completer<bool>();
+
+  Directory dir =
+      Directory.systemTemp.createTempSync('dart_file_system_watcher');
+  var file = new File(join(dir.path, 'file'));
+  file.createSync();
+
+  Isolate isolate =
+      await Isolate.spawn(watcher, receivePort.sendPort, paused: true);
+
+  var subscription;
+  subscription = receivePort.listen((object) async {
+    if (object == 'end') {
+      exiting.complete(true);
+      subscription.cancel();
+      // Clean up the directory and files
+      dir.deleteSync(recursive: true);
+      asyncEnd();
+    } else if (object == 'start') {
+      isolate.pause(isolate.pauseCapability);
+      // Populate the buffer to overflows and check for exception
+      for (int i = 0; i < 2000; i++) {
+        file.writeAsStringSync('a');
+      }
+      isolate.resume(isolate.pauseCapability);
+    }
+  });
+  // Resume paused isolate to create watcher
+  isolate.resume(isolate.pauseCapability);
+
+  await exiting.future;
+  isolate.kill();
+}
+
+void watcher(SendPort sendPort) async {
+  runZoned(() {
+    var watcher = Directory.systemTemp.watch(recursive: true);
+    watcher.listen((data) async {});
+    sendPort.send('start');
+  }, onError: (error) {
+    print(error);
+    sendPort.send('end');
+  });
+}
+
 void main() {
   if (!FileSystemEntity.isWatchSupported) return;
   testWatchCreateFile();
@@ -414,4 +472,5 @@
   testWatchNonExisting();
   testWatchMoveSelf();
   testWatchConsistentModifiedFile();
+  if (Platform.isWindows) testWatchOverflow();
 }
diff --git a/tools/VERSION b/tools/VERSION
index 915faac..528e6b2 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -33,7 +33,7 @@
 MAJOR 2
 MINOR 6
 PATCH 0
-PRERELEASE 7
+PRERELEASE 8
 PRERELEASE_PATCH 0
-ABI_VERSION 17
-OLDEST_SUPPORTED_ABI_VERSION 16
+ABI_VERSION 19
+OLDEST_SUPPORTED_ABI_VERSION 18
diff --git a/tools/approve_results.dart b/tools/approve_results.dart
index dc39a52..7c409cf 100755
--- a/tools/approve_results.dart
+++ b/tools/approve_results.dart
@@ -489,6 +489,9 @@
         exitCode = 1;
         return;
       }
+      if (object["builds"] == null) {
+        break;
+      }
       builds.addAll(object["builds"]);
       cursor = object["next_cursor"];
     } while (cursor != null);
diff --git a/tools/apps/update_homebrew/lib/src/impl.dart b/tools/apps/update_homebrew/lib/src/impl.dart
index 2c17713..4d4cf86 100644
--- a/tools/apps/update_homebrew/lib/src/impl.dart
+++ b/tools/apps/update_homebrew/lib/src/impl.dart
@@ -1,13 +1,21 @@
 part of '../update_homebrew.dart';
 
 const _files = {
-  'dev': [_x64File, _ia32File],
-  'stable': [_x64File, _ia32File]
+  'dev': [_x64Files, _ia32Files],
+  'stable': [_x64Files, _ia32Files]
 };
 
 const _urlBase = 'https://storage.googleapis.com/dart-archive/channels';
-const _x64File = 'sdk/dartsdk-macos-x64-release.zip';
-const _ia32File = 'sdk/dartsdk-macos-ia32-release.zip';
+const _x64Files = {
+  'mac': 'sdk/dartsdk-macos-x64-release.zip',
+  'linux': 'sdk/dartsdk-linux-x64-release.zip',
+  'linux-arm': 'sdk/dartsdk-linux-arm64-release.zip',
+};
+const _ia32Files = {
+  'mac': 'sdk/dartsdk-macos-ia32-release.zip',
+  'linux': 'sdk/dartsdk-linux-ia32-release.zip',
+  'linux-arm': 'sdk/dartsdk-linux-arm-release.zip',
+};
 
 Future<String> _getHash256(
     String channel, String revision, String download) async {
@@ -66,9 +74,11 @@
   var hashes = <String, Map>{};
   for (var channel in supportedChannels) {
     hashes[channel] = {};
-    for (var file in _files[channel]) {
-      var hash = await _getHash256(channel, revisions[channel], file);
-      hashes[channel][file] = hash;
+    for (var files in _files[channel]) {
+      for (var file in files.values) {
+        var hash = await _getHash256(channel, revisions[channel], file);
+        hashes[channel][file] = hash;
+      }
     }
   }
   return hashes;
@@ -82,22 +92,58 @@
   homepage "https://www.dartlang.org/"
 
   version "$stableVersion"
-  if Hardware::CPU.is_64_bit?
-    url "$_urlBase/stable/release/${revisions['stable']}/$_x64File"
-    sha256 "${hashes['stable'][_x64File]}"
-  else
-    url "$_urlBase/stable/release/${revisions['stable']}/$_ia32File"
-    sha256 "${hashes['stable'][_ia32File]}"
+  if OS.mac?
+    if Hardware::CPU.is_64_bit?
+      url "$_urlBase/stable/release/${revisions['stable']}/${_x64Files['mac']}"
+      sha256 "${hashes['stable'][_x64Files['mac']]}"
+    else
+      url "$_urlBase/stable/release/${revisions['stable']}/${_ia32Files['mac']}"
+      sha256 "${hashes['stable'][_ia32Files['mac']]}"
+    end
+  elsif OS.linux? && Hardware::CPU.intel?
+    if Hardware::CPU.is_64_bit?
+      url "$_urlBase/stable/release/${revisions['stable']}/${_x64Files['linux']}"
+      sha256 "${hashes['stable'][_x64Files['linux']]}"
+    else
+      url "$_urlBase/stable/release/${revisions['stable']}/${_ia32Files['linux']}"
+      sha256 "${hashes['stable'][_ia32Files['linux']]}"
+    end
+  elsif OS.linux? && Hardware::CPU.arm?
+    if Hardware::CPU.is_64_bit?
+      url "$_urlBase/stable/release/${revisions['stable']}/${_x64Files['linux-arm']}"
+      sha256 "${hashes['stable'][_x64Files['linux-arm']]}"
+    else
+      url "$_urlBase/stable/release/${revisions['stable']}/${_ia32Files['linux-arm']}"
+      sha256 "${hashes['stable'][_ia32Files['linux-arm']]}"
+    end
   end
 
   devel do
     version "$devVersion"
-    if Hardware::CPU.is_64_bit?
-      url "$_urlBase/dev/release/${revisions['dev']}/$_x64File"
-      sha256 "${hashes['dev'][_x64File]}"
-    else
-      url "$_urlBase/dev/release/${revisions['dev']}/$_ia32File"
-      sha256 "${hashes['dev'][_ia32File]}"
+    if OS.mac?
+      if Hardware::CPU.is_64_bit?
+        url "$_urlBase/dev/release/${revisions['dev']}/${_x64Files['mac']}"
+        sha256 "${hashes['dev'][_x64Files['mac']]}"
+      else
+        url "$_urlBase/dev/release/${revisions['dev']}/${_ia32Files['mac']}"
+        sha256 "${hashes['dev'][_ia32Files['mac']]}"
+      end
+    elsif OS.linux? && Hardware::CPU.intel?
+      if Hardware::CPU.is_64_bit?
+        url "$_urlBase/dev/release/${revisions['dev']}/${_x64Files['linux']}"
+        sha256 "${hashes['dev'][_x64Files['linux']]}"
+      else
+        url "$_urlBase/dev/release/${revisions['dev']}/${_ia32Files['linux']}"
+        sha256 "${hashes['dev'][_ia32Files['linux']]}"
+      end
+    elsif OS.linux? && Hardware::CPU.arm?
+      if Hardware::CPU.is_64_bit?
+        url "$_urlBase/dev/release/${revisions['dev']}/${_x64Files['linux-arm']}"
+        sha256 "${hashes['dev'][_x64Files['linux-arm']]}"
+      else
+        url "$_urlBase/dev/release/${revisions['dev']}/${_ia32Files['linux-arm']}"
+        sha256 "${hashes['dev'][_ia32Files['linux-arm']]}"
+      end
     end
   end
 
diff --git a/tools/bots/README.md b/tools/bots/README.md
index c430c6d..706c5b4 100644
--- a/tools/bots/README.md
+++ b/tools/bots/README.md
@@ -1,14 +1,20 @@
 # tools/bots
+
 This folder contains scripts and configuration files used by Dart's continuous
 integration and testing infrastructure.
 
 ## Test matrix
+
 The file `test_matrix.json` defines the test configurations run by Dart's CI
 infrastructure. Changes to the test matrix affect all builds that include them.
 
 ### Structure
-The test matrix is a JSON document and consists of the `"filesets"` object and
-the `"configurations"` array.
+
+The test matrix is a JSON document and consists of the `"filesets"` object, the
+`"configurations"` list, and the `"builder_configurations"` list as well as a
+`"global"` values object and a `"branches"` list.
+
+### Filesets
 
 The file sets define files and/or directories that need to be present for a test
 configuration at runtime. Any directory specified will be included along with
@@ -28,13 +34,39 @@
 }
 ```
 
-The builder configurations describe all test configurations a specific builder
+### Configurations
+
+The configurations describe all named configurations that the CI infrastructure
+supports. It consists of a list of configuration descriptions.
+
+Each configuration description defines one or more configuration names using a
+simple template syntax, where a group `(a|b|c)` means taking each of the
+options for a different configuration name. The set of all configuration names
+is the result of picking each combination of group options.
+
+The configuration name implicitly defines the options of the configuration
+(system, architecture, compiler, etc.), but additional options can be given in
+an `options` field.
+
+```json
+"configurations": {
+  "unittest-(linux|win|mac)": {
+    "options": {
+      "compiler": "dartk",
+      "mode": "release",
+}},
+```
+
+
+### Builder Configurations
+
+The builder configurations describes all test configurations a specific builder
 must execute. Each builder configuration is an object that specifies which
 builders it applies to, defines the build steps for the builders, and some
 additional metadata. Only one builder configuration can apply to a builder.
 
 ```json
-"configurations": [
+"builder_configurations": [
   {
     "builders": [
       "a-builder",
@@ -53,6 +85,12 @@
 run instead of the default script: `tools/test.py`. Additional arguments may be
 specified. These arguments will be passed to the script.
 
+Inside arguments, the following variables will be expanded to values extracted
+from the builder name:
+- `${mode}`: the mode in which to run the tests; e.g., `release`, `debug`
+- `${arch}`: architecture to run the tests on; e.g., `ia32`, `x64`
+- `$[system}`: the system on which to run the tests; e.g., `win`, `linux`, `mac`
+
 ```json
 "steps": [
   {
@@ -62,10 +100,15 @@
   },
   {
     "name": "test it",
+    "arguments": ["-nconfiguration-${system}"]
   }
 ]
 ```
 
+A step that uses the script `tools/test.py` either explicitely or by default is
+called a "test step". Test steps must include the `-n` command line argument to
+select one of the named configurations defined in the `configurations` section.
+
 A step using the default script may also be sharded across many machines using
 the `"shards"` parameter. If a step is sharded, it must specify a `"fileset"`.
 Only the files and directories defined by the file set will be available to the
@@ -79,11 +122,13 @@
 }
 ```
 
+## Builders
+
 ### Builder name parsing
 The builder names are split by '-' and each part is then examined if it is an
 option. Options can be runtimes (e.g. "chrome"), architectures (e.g. x64) and
 operating system families (e.g. win). For each valid option, additional
-arguments are passed to the `tools/test.py` and `tools/build.py` scripts.
+arguments are passed to the `tools/build.py` script.
 
 ### Adding a new builder
 To add a builder:
diff --git a/tools/bots/aot_smoke_tests.dart b/tools/bots/aot_smoke_tests.dart
index fba0c9d..0e912cd 100755
--- a/tools/bots/aot_smoke_tests.dart
+++ b/tools/bots/aot_smoke_tests.dart
@@ -3,7 +3,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.
 
-// Smoke test runner for Dart AOT (dart2aot, dartaotruntime).
+// Smoke test runner for Dart AOT (dart2native, dartaotruntime).
 // aot_smoke_tests.dart and dart_aot_test.dart together form the test that the
 // AOT toolchain is compiled and included correctly in the SDK.
 // This tests that the AOT tools can both successfully compile Dart -> AOT and
@@ -20,7 +20,6 @@
 final String scriptSuffix = Platform.isWindows ? ".bat" : "";
 final String executableSuffix = Platform.isWindows ? ".exe" : "";
 final String sdkBinDir = path.dirname(Platform.executable);
-final String dart2aot = path.join(sdkBinDir, 'dart2aot${scriptSuffix}');
 final String dartaotruntime =
     path.join(sdkBinDir, 'dartaotruntime${executableSuffix}');
 final String dart2native = path.join(sdkBinDir, 'dart2native${scriptSuffix}');
@@ -35,30 +34,6 @@
 }
 
 void main(List<String> args) {
-  test("dart2aot: Can compile and run AOT", () async {
-    await withTempDir((String tmp) async {
-      final String testCode = path.join('tools', 'bots', 'dart_aot_test.dart');
-      final String tmpAot = path.join(tmp, 'dart_aot_test.aot');
-
-      {
-        final ProcessResult result =
-            await Process.run(dart2aot, [testCode, tmpAot]);
-        expect(result.stderr, '');
-        expect(result.exitCode, 0);
-        expect(result.stdout, '');
-      }
-
-      {
-        const String testStr = 'Dart AOT';
-        final ProcessResult result =
-            await Process.run(dartaotruntime, [tmpAot, testStr]);
-        expect(result.stderr, '');
-        expect(result.exitCode, 0);
-        expect(result.stdout, 'Hello, ${testStr}.${newline}');
-      }
-    });
-  });
-
   test("dart2native: Can compile and run AOT", () async {
     await withTempDir((String tmp) async {
       final String testCode = path.join('tools', 'bots', 'dart_aot_test.dart');
diff --git a/tools/bots/dart_aot_test.dart b/tools/bots/dart_aot_test.dart
index 36abe33..a1657c1 100755
--- a/tools/bots/dart_aot_test.dart
+++ b/tools/bots/dart_aot_test.dart
@@ -3,7 +3,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.
 
-// Test program for Dart AOT (dart2aot, dartaotruntime).
+// Test program for Dart AOT (dart2native, dartaotruntime).
 
 void main(List<String> args) async {
   final String who = !args.isEmpty ? args[0] : '世界';
diff --git a/tools/bots/flutter/compile_flutter.sh b/tools/bots/flutter/compile_flutter.sh
index b86d351..7a3345e 100755
--- a/tools/bots/flutter/compile_flutter.sh
+++ b/tools/bots/flutter/compile_flutter.sh
@@ -48,4 +48,4 @@
 
 popd
 
-$dart --enable-asserts pkg/vm/test/frontend_server_flutter.dart --flutterDir=$tmpdir/flutter --flutterPlatformDir=$tmpdir/flutter_patched_sdk
+$dart --enable-asserts pkg/frontend_server/test/frontend_server_flutter.dart --flutterDir=$tmpdir/flutter --flutterPlatformDir=$tmpdir/flutter_patched_sdk
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index 0cc4ec9..fd499cb 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -55,6 +55,44 @@
       "xcodebuild/ReleaseX64/dart-sdk/",
       "xcodebuild/ReleaseX64/gen/utils/dartdevc/"
     ],
+    "dart2js_nnbd": [
+      ".packages",
+      "out/ReleaseIA32NNBD/dart-sdk/",
+      "out/ReleaseX64NNBD/dart-sdk/",
+      "out/ReleaseX64NNBD/gen/utils/dartdevc/",
+      "pkg/",
+      "runtime/tests/",
+      "samples-dev/",
+      "samples/",
+      "sdk_nnbd/",
+      "tests/angular/",
+      "tests/co19_2/co19_2-analyzer.status",
+      "tests/co19_2/co19_2-dart2js.status",
+      "tests/co19_2/co19_2-dartdevc.status",
+      "tests/co19_2/co19_2-kernel.status",
+      "tests/co19_2/co19_2-runtime.status",
+      "tests/compiler/",
+      "tests/corelib_2/",
+      "tests/dart/",
+      "tests/kernel/",
+      "tests/language_2/",
+      "tests/lib_2/",
+      "tests/light_unittest.dart",
+      "tests/search/",
+      "tests/standalone/",
+      "tests/standalone_2/",
+      "tests/ffi/",
+      "third_party/babel/babel.min.js",
+      "third_party/d8/",
+      "third_party/observatory_pub_packages/packages/web_components/",
+      "third_party/pkg/",
+      "third_party/pkg_tested/",
+      "third_party/requirejs/",
+      "tools/",
+      "xcodebuild/ReleaseIA32NNBD/dart-sdk/",
+      "xcodebuild/ReleaseX64NNBD/dart-sdk/",
+      "xcodebuild/ReleaseX64NNBD/gen/utils/dartdevc/"
+    ],
     "dart2js_hostasserts": [
       ".packages",
       "out/ReleaseIA32/dart",
@@ -300,6 +338,11 @@
         "builder-tag": "tsan",
         "timeout": 240
     }},
+    "dartk-ubsan-(linux|mac|win)-(debug|product|release)-(ia32|x64)": {
+      "options": {
+        "builder-tag": "ubsan",
+        "timeout": 240
+    }},
     "dart2js-(linux|mac|win)-chrome": {
       "options": {
         "use-sdk": true
@@ -356,7 +399,12 @@
         "minified": true,
         "use-sdk": true
     }},
-    "dartkp-android-(debug|product|release)-(arm|arm64|arm_x64)": {
+    "dartkp-android-(debug|product|release)-arm_x64": {
+      "options": {
+        "builder-tag": "crossword",
+        "use-elf": true
+    }},
+    "dartkp-android-(debug|product|release)-(arm|arm64)": {
       "options": {
         "use-elf": true
     }},
@@ -365,11 +413,11 @@
       "options": {
         "use-blobs": true
     }},
-    "dartkp-linux-(debug|product|release)-(simarm|simarm64)-crossword": {
+    "dartkp-linux-(debug|product|release)-simarm-crossword": {
       "options": {
         "builder-tag": "crossword"
     }},
-    "dartkp-(win|mac)-(debug|product|release)-(simarm|simarm64)-crossword": {
+    "dartkp-(win|mac)-(debug|product|release)-simarm-crossword": {
       "options": {
         "builder-tag": "crossword",
         "use-blobs": true
@@ -446,6 +494,12 @@
         "checked": true,
         "use-sdk": true
     }},
+    "dartdevc-strong-linux-release-chrome": {
+      "options": {
+        "checked": true,
+        "use-sdk": true,
+        "enable-experiment": ["non-nullable"]
+    }},
     "fasta-(linux|mac|win)": { },
     "analyzer-(linux|mac|win)": {
       "options": {
@@ -794,23 +848,30 @@
         "vm-kernel-asan-linux-release-x64"
       ],
       "meta": {
-        "description": "This configuration is used by the vm builders with address sanitizing (asan). We have to run gn.py with the DART_USE_ASAN options, which we do by running generate_buildfiles."
+        "description": "This configuration is used by the vm builders with AddressSanitizer (asan)."
       },
       "steps": [
         {
+          "name": "configure dart",
+          "script": "tools/gn.py",
+          "arguments": [
+            "--mode=${mode}",
+            "--arch=${arch}",
+            "--asan"
+          ]
+        },
+        {
           "name": "build dart",
           "script": "tools/build.py",
           "arguments": ["runtime"],
           "environment": {
-            "DART_USE_ASAN": 1,
             "ASAN_OPTIONS": "handle_segv=0:detect_leaks=1:detect_stack_use_after_return=0:disable_coredump=0:abort_on_error=1",
             "ASAN_SYMBOLIZER_PATH": "buildtools/linux-x64/clang/bin/llvm-symbolizer"
           }
         },
         {
           "name": "vm tests",
-          "arguments": [
-            "-ndartk-asan-linux-release-${arch}"],
+          "arguments": ["-ndartk-asan-linux-release-${arch}"],
           "environment": {
             "ASAN_OPTIONS": "handle_segv=0:detect_leaks=1:detect_stack_use_after_return=0:disable_coredump=0:abort_on_error=1",
             "ASAN_SYMBOLIZER_PATH": "buildtools/linux-x64/clang/bin/llvm-symbolizer"
@@ -824,23 +885,30 @@
         "vm-kernel-lsan-linux-release-x64"
       ],
       "meta": {
-        "description": "This configuration is used by the vm builders with leak sanitizing (lsan). We have to run gn.py with the DART_USE_LSAN options, which we do by running generate_buildfiles."
+        "description": "This configuration is used by the vm builders with LeakSanitizer (lsan)."
       },
       "steps": [
         {
+          "name": "configure dart",
+          "script": "tools/gn.py",
+          "arguments": [
+            "--mode=${mode}",
+            "--arch=${arch}",
+            "--lsan"
+          ]
+        },
+        {
           "name": "build dart",
           "script": "tools/build.py",
           "arguments": ["runtime"],
           "environment": {
-            "DART_USE_LSAN": 1,
             "ASAN_OPTIONS": "handle_segv=0:detect_leaks=1:detect_stack_use_after_return=0:disable_coredump=0:abort_on_error=1",
             "ASAN_SYMBOLIZER_PATH": "buildtools/linux-x64/clang/bin/llvm-symbolizer"
           }
         },
         {
           "name": "vm tests",
-          "arguments": [
-            "-ndartk-lsan-linux-release-${arch}"],
+          "arguments": ["-ndartk-lsan-linux-release-${arch}"],
           "environment": {
             "ASAN_OPTIONS": "handle_segv=0:detect_leaks=1:detect_stack_use_after_return=0:disable_coredump=0:abort_on_error=1",
             "ASAN_SYMBOLIZER_PATH": "buildtools/linux-x64/clang/bin/llvm-symbolizer"
@@ -854,15 +922,23 @@
         "vm-kernel-msan-linux-release-x64"
       ],
       "meta": {
-        "description": "This configuration is used by the vm builders with memory sanitizing (msan). We have to run gn.py with the DART_USE_MSAN options, which we do by running generate_buildfiles."
+        "description": "This configuration is used by the vm builders with MemorySanitizer (msan)."
       },
       "steps": [
         {
+          "name": "configure dart",
+          "script": "tools/gn.py",
+          "arguments": [
+            "--mode=${mode}",
+            "--arch=${arch}",
+            "--msan"
+          ]
+        },
+        {
           "name": "build dart",
           "script": "tools/build.py",
           "arguments": ["runtime"],
           "environment": {
-            "DART_USE_MSAN": 1,
             "MSAN_OPTIONS": "handle_segv=0:detect_leaks=1:detect_stack_use_after_return=0:disable_coredump=0:abort_on_error=1",
             "MSAN_SYMBOLIZER_PATH": "buildtools/linux-x64/clang/bin/llvm-symbolizer"
           }
@@ -883,23 +959,30 @@
         "vm-kernel-tsan-linux-release-x64"
       ],
       "meta": {
-        "description": "This configuration is used by the vm builders with thread sanitizing (tsan). We have to run gn.py with the DART_USE_TSAN options, which we do by running generate_buildfiles."
+        "description": "This configuration is used by the vm builders with ThreadSanitizer (tsan)."
       },
       "steps": [
         {
+          "name": "configure dart",
+          "script": "tools/gn.py",
+          "arguments": [
+            "--mode=${mode}",
+            "--arch=${arch}",
+            "--tsan"
+          ]
+        },
+        {
           "name": "build dart",
           "script": "tools/build.py",
           "arguments": ["runtime"],
           "environment": {
-            "DART_USE_TSAN": 1,
             "TSAN_OPTIONS": "handle_segv=0:disable_coredump=0:abort_on_error=1",
             "TSAN_SYMBOLIZER_PATH": "buildtools/linux-x64/clang/bin/llvm-symbolizer"
           }
         },
         {
           "name": "vm tests",
-          "arguments": [
-            "-ndartk-tsan-linux-release-${arch}"],
+          "arguments": ["-ndartk-tsan-linux-release-${arch}"],
           "environment": {
             "TSAN_OPTIONS": "handle_segv=0:disable_coredump=0:abort_on_error=1",
             "TSAN_SYMBOLIZER_PATH": "buildtools/linux-x64/clang/bin/llvm-symbolizer"
@@ -909,6 +992,41 @@
     },
     {
       "builders": [
+        "vm-kernel-ubsan-linux-release-ia32",
+        "vm-kernel-ubsan-linux-release-x64"
+      ],
+      "meta": {
+        "description": "This configuration is used by the vm builders with UndefinedBehaviorSanitizer (ubsan)."
+      },
+      "steps": [
+        {
+          "name": "configure dart",
+          "script": "tools/gn.py",
+          "arguments": [
+            "--mode=${mode}",
+            "--arch=${arch}",
+            "--ubsan"
+          ]
+        },
+        {
+          "name": "build dart",
+          "script": "tools/build.py",
+          "arguments": ["runtime"],
+          "environment": {
+            "UBSAN_OPTIONS": "handle_segv=0:disable_coredump=0:abort_on_error=1"
+          }
+        },
+        {
+          "name": "vm tests",
+          "arguments": ["-ndartk-ubsan-linux-release-${arch}"],
+          "environment": {
+            "UBSAN_OPTIONS": "handle_segv=0:disable_coredump=0:abort_on_error=1"
+          }
+        }
+      ]
+    },
+    {
+      "builders": [
         "vm-kernel-linux-release-simarm",
         "vm-kernel-linux-release-simarm64",
         "vm-kernel-linux-release-ia32",
@@ -1224,6 +1342,30 @@
     },
     {
       "builders": [
+        "ddc-nnbd-linux-release-chrome"
+      ],
+      "meta": {
+        "description": "This configuration is used by the ddc nnbd builder group."
+      },
+      "steps": [
+        {
+          "name": "build dart",
+          "script": "tools/build.py",
+          "arguments": ["--nnbd", "dartdevc_test"]
+        },
+        {
+          "name": "ddc nnbd strong tests",
+          "arguments": [
+            "-ndartdevc-strong-linux-release-chrome",
+            "dartdevc_native"
+          ],
+          "shards": 1,
+          "fileset": "dart2js_nnbd"
+        }
+      ]
+    },
+    {
+      "builders": [
         "ddc-mac-release-chrome"
       ],
       "meta": {
@@ -1709,10 +1851,10 @@
                         "--mode=release", "create_sdk"]
         },
         {
-          "name": "build gen_kernel.dart.snapshot and dart2aot",
+          "name": "build gen_kernel.dart.snapshot",
           "script": "tools/build.py",
           "arguments": ["--arch=x64,arm,arm64", "--mode=release",
-                        "copy_gen_kernel_snapshot", "copy_dart2aot"]
+                        "copy_gen_kernel_snapshot"]
         },
         {
           "name": "build gen_snapshot and dartaotruntime",
@@ -1759,10 +1901,10 @@
                         "--mode=release", "create_sdk"]
         },
         {
-          "name": "build gen_kernel.dart.snapshot and dart2aot",
+          "name": "build gen_kernel.dart.snapshot",
           "script": "tools/build.py",
           "arguments": ["--arch=x64", "--mode=release",
-                        "copy_gen_kernel_snapshot", "copy_dart2aot"]
+                        "copy_gen_kernel_snapshot"]
         },
         {
           "name": "build gen_snapshot and dartaotruntime",
@@ -1796,10 +1938,10 @@
                         "--mode=release", "create_sdk", "runtime_kernel"]
         },
         {
-          "name": "build gen_kernel.dart.snapshot and dart2aot",
+          "name": "build gen_kernel.dart.snapshot",
           "script": "tools/build.py",
           "arguments": ["--arch=x64", "--mode=release",
-                        "copy_gen_kernel_snapshot", "copy_dart2aot"]
+                        "copy_gen_kernel_snapshot"]
         },
         {
           "name": "build gen_snapshot and dartaotruntime",
diff --git a/tools/bots/try_benchmarks.sh b/tools/bots/try_benchmarks.sh
index 882e1d3..88e7753 100755
--- a/tools/bots/try_benchmarks.sh
+++ b/tools/bots/try_benchmarks.sh
@@ -89,6 +89,7 @@
       -- \
       third_party/d8/linux/ia32/natives_blob.bin \
       third_party/d8/linux/ia32/snapshot_blob.bin \
+      out/ReleaseIA32/dart2js_platform.dill \
       out/ReleaseIA32/vm_outline_strong.dill \
       out/ReleaseIA32/vm_platform_strong.dill \
       out/ReleaseIA32/gen/kernel_service.dill \
@@ -174,6 +175,7 @@
       -- \
       third_party/d8/linux/ia32/natives_blob.bin \
       third_party/d8/linux/ia32/snapshot_blob.bin \
+      out/ReleaseIA32/dart2js_platform.dill \
       out/ReleaseIA32/vm_outline_strong.dill \
       out/ReleaseIA32/vm_platform_strong.dill \
       out/ReleaseIA32/gen/kernel_service.dill \
@@ -254,6 +256,7 @@
       -- \
       third_party/d8/linux/x64/natives_blob.bin \
       third_party/d8/linux/x64/snapshot_blob.bin \
+      out/ReleaseX64/dart2js_platform.dill \
       out/ReleaseX64/vm_outline_strong.dill \
       out/ReleaseX64/vm_platform_strong.dill \
       out/ReleaseX64/gen/kernel_service.dill \
@@ -358,6 +361,7 @@
       -- \
       third_party/d8/linux/x64/natives_blob.bin \
       third_party/d8/linux/x64/snapshot_blob.bin \
+      out/ReleaseX64/dart2js_platform.dill \
       out/ReleaseX64/vm_outline_strong.dill \
       out/ReleaseX64/vm_platform_strong.dill \
       out/ReleaseX64/gen/kernel_service.dill \
diff --git a/tools/dom/scripts/systemnative.py b/tools/dom/scripts/systemnative.py
index 5abcb92..296bd67 100644
--- a/tools/dom/scripts/systemnative.py
+++ b/tools/dom/scripts/systemnative.py
@@ -22,8 +22,7 @@
     'protocol', 'search', 'username'
 ]
 
-_promise_to_future = Conversion('convertNativePromiseToDartFuture', 'dynamic',
-                                'Future')
+_promise_to_future = Conversion('promiseToFuture', 'dynamic', 'Future')
 
 
 def array_type(data_type):
diff --git a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
index 83a8aa6..28a7164 100644
--- a/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
+++ b/tools/dom/templates/html/dart2js/html_dart2js.darttemplate
@@ -52,8 +52,9 @@
     setDispatchProperty;
 import 'dart:_foreign_helper' show JS, JS_INTERCEPTOR_CONSTANT;
 
-export 'dart:math' show Rectangle, Point;
 export 'dart:_internal' show HttpStatus;
+export 'dart:html_common' show promiseToFuture;
+export 'dart:math' show Rectangle, Point;
 
 $!GENERATED_DART_FILES
 
@@ -109,33 +110,13 @@
 HtmlDocument get document =>
     JS('returns:HtmlDocument;depends:none;effects:none;gvn:true', 'document');
 
-// Supoort to convert JS Promise to a Dart Future.
-Future<T> promiseToFuture<T>(jsPromise) {
-  var completer = new Completer<T>();
-
-  var thenSuccessCode = (promiseValue) => completer.complete(promiseValue);
-  var thenErrorCode = (promiseError) => completer.completeError(promiseError);
-
-  JS("", "#.then(#, #)", jsPromise, convertDartClosureToJS(thenSuccessCode, 1),
-      convertDartClosureToJS(thenErrorCode, 1));
-
-  return completer.future;
-}
-
-// Supoort to convert JS Promise to a Dart Future<Map<String, dynamic>>.  Each property of the JS
-// object is added to the Map as a key of type String with a value of type dynamic.
-Future<Map<String, dynamic>> promiseToFutureAsMap(jsPromise) {
-  var completer = new Completer<Map<String, dynamic>>();
-
-  var thenSuccessCode = (promiseValue) =>
-      completer.complete(convertNativeToDart_Dictionary(promiseValue));
-  var thenErrorCode = (promiseError) => completer.completeError(promiseError);
-
-  JS("", "#.then(#, #)", jsPromise, convertDartClosureToJS(thenSuccessCode, 1),
-      convertDartClosureToJS(thenErrorCode, 1));
-
-  return completer.future;
-}
+/// Convert a JS Promise to a Future<Map<String, dynamic>>.
+///
+/// On a successful result the native JS result will be converted to a Dart Map.
+/// See [convertNativeToDart_Dictionary]. On a rejected promise the error is
+/// forwarded without change.
+Future<Map<String, dynamic>> promiseToFutureAsMap(jsPromise) =>
+  promiseToFuture(jsPromise).then(convertNativeToDart_Dictionary);
 
 // Workaround for tags like <cite> that lack their own Element subclass --
 // Dart issue 1990.
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index 8783228..3fd0d4e 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -880,7 +880,7 @@
    * [timing] paramter can be a double, representing the number of milliseconds
    * for the transition, or a Map with fields corresponding to those
    * of the [Timing] object.
-  **/
+   */
   @SupportedBrowser(SupportedBrowser.CHROME, '36')
   Animation animate(Iterable<Map<String, dynamic>> frames, [timing]) {
     if (frames is! Iterable || !(frames.every((x) => x is Map))) {
diff --git a/tools/gn.py b/tools/gn.py
index 14f5a4b..385a411 100755
--- a/tools/gn.py
+++ b/tools/gn.py
@@ -23,6 +23,7 @@
 DART_USE_LSAN = "DART_USE_LSAN"  # Use instead of --lsan
 DART_USE_MSAN = "DART_USE_MSAN"  # Use instead of --msan
 DART_USE_TSAN = "DART_USE_TSAN"  # Use instead of --tsan
+DART_USE_UBSAN = "DART_USE_UBSAN"  # Use instead of --ubsan
 DART_USE_TOOLCHAIN = "DART_USE_TOOLCHAIN"  # Use instread of --toolchain-prefix
 DART_USE_SYSROOT = "DART_USE_SYSROOT"  # Use instead of --target-sysroot
 DART_USE_CRASHPAD = "DART_USE_CRASHPAD"  # Use instead of --use-crashpad
@@ -48,6 +49,10 @@
     return DART_USE_TSAN in os.environ
 
 
+def UseUBSAN():
+    return DART_USE_UBSAN in os.environ
+
+
 def ToolchainPrefix(args):
     if args.toolchain_prefix:
         return args.toolchain_prefix
@@ -157,7 +162,7 @@
 
 
 def UseSanitizer(args):
-    return args.asan or args.lsan or args.msan or args.tsan
+    return args.asan or args.lsan or args.msan or args.tsan or args.ubsan
 
 
 def DontUseClang(args, target_os, host_cpu, target_cpu):
@@ -257,6 +262,7 @@
     gn_args['is_lsan'] = args.lsan and gn_args['is_clang']
     gn_args['is_msan'] = args.msan and gn_args['is_clang']
     gn_args['is_tsan'] = args.tsan and gn_args['is_clang']
+    gn_args['is_ubsan'] = args.ubsan and gn_args['is_clang']
 
     if not args.platform_sdk and not gn_args['target_cpu'].startswith('arm'):
         gn_args['dart_platform_sdk'] = args.platform_sdk
@@ -428,15 +434,10 @@
     other_group.add_argument(
         '--bytecode',
         '-b',
-        help='Use bytecode in Dart VM',
-        default=True,
+        help='Include bytecode in the VMs platform dill',
+        default=False,
         action="store_true")
     other_group.add_argument(
-        '--no-bytecode',
-        help='Disable bytecode in Dart VM',
-        dest='bytecode',
-        action="store_false")
-    other_group.add_argument(
         '--clang', help='Use Clang', default=True, action='store_true')
     other_group.add_argument(
         '--no-clang', help='Disable Clang', dest='clang', action='store_false')
@@ -505,6 +506,13 @@
     other_group.add_argument(
         '--no-tsan', help='Disable TSAN', dest='tsan', action='store_false')
     other_group.add_argument(
+        '--ubsan',
+        help='Build with UBSAN',
+        default=UseUBSAN(),
+        action='store_true')
+    other_group.add_argument(
+        '--no-ubsan', help='Disable UBSAN', dest='ubsan', action='store_false')
+    other_group.add_argument(
         '--wheezy',
         help='This flag is deprecated.',
         default=True,
diff --git a/tools/linux_dist_support/debian/rules b/tools/linux_dist_support/debian/rules
index 2ec324f..c6893d7 100755
--- a/tools/linux_dist_support/debian/rules
+++ b/tools/linux_dist_support/debian/rules
@@ -40,7 +40,7 @@
 ifneq (,$(findstring $(DEB_HOST_ARCH_CPU),$(AOT_SUPPORTED_ARCHS)))
 AOT_BUILD_CMD := \
 python tools/build.py -v -m release -a $(ARCH) $(TOOLCHAIN) \
-		copy_gen_kernel_snapshot copy_dart2aot; \
+		copy_gen_kernel_snapshot; \
 python tools/build.py -v -m product -a $(ARCH) $(TOOLCHAIN) \
 		copy_gen_snapshot copy_dartaotruntime; \
 mkdir -p out/$(BUILD_TYPE)/dart-sdk/bin/utils; \
diff --git a/tools/patches/flutter-engine/8ba6f7e2eb8ac44b6de3e87a3062d1c8e34b6cc1.patch b/tools/patches/flutter-engine/8ba6f7e2eb8ac44b6de3e87a3062d1c8e34b6cc1.patch
index 408eb4f..56ac868 100644
--- a/tools/patches/flutter-engine/8ba6f7e2eb8ac44b6de3e87a3062d1c8e34b6cc1.patch
+++ b/tools/patches/flutter-engine/8ba6f7e2eb8ac44b6de3e87a3062d1c8e34b6cc1.patch
@@ -1,3 +1,29 @@
+From 6fefdfc884fb7858bd8cd981e1fdb493da8088b4 Mon Sep 17 00:00:00 2001
+From: Alexander Aprelev <aam@google.com>
+Date: Mon, 7 Oct 2019 23:13:33 -0700
+Subject: [PATCH] 2
+
+---
+ BUILD.gn                                      |  2 +-
+ ci/analyze.sh                                 |  6 +-
+ .../.gitignore                                |  0
+ flutter_frontend_server/BUILD.gn              | 63 +++++++++++++++++
+ .../README.md                                 |  0
+ .../bin/starter.dart                          |  2 +-
+ .../lib/server.dart                           |  2 +-
+ .../package_incremental.py                    |  8 +--
+ .../pubspec.yaml                              |  0
+ frontend_server/BUILD.gn                      | 68 ++-----------------
+ tools/generate_package_files.py               |  2 +-
+ 11 files changed, 80 insertions(+), 73 deletions(-)
+ rename {frontend_server => flutter_frontend_server}/.gitignore (100%)
+ create mode 100644 flutter_frontend_server/BUILD.gn
+ rename {frontend_server => flutter_frontend_server}/README.md (100%)
+ rename {frontend_server => flutter_frontend_server}/bin/starter.dart (76%)
+ rename {frontend_server => flutter_frontend_server}/lib/server.dart (98%)
+ rename {frontend_server => flutter_frontend_server}/package_incremental.py (94%)
+ rename {frontend_server => flutter_frontend_server}/pubspec.yaml (100%)
+
 diff --git a/BUILD.gn b/BUILD.gn
 index b894fe26f..e4ce1dea1 100644
 --- a/BUILD.gn
@@ -11,6 +37,25 @@
          "//third_party/dart:create_sdk",
        ]
  
+diff --git a/ci/analyze.sh b/ci/analyze.sh
+index 9ee12a913..6b48c9447 100755
+--- a/ci/analyze.sh
++++ b/ci/analyze.sh
+@@ -18,11 +18,11 @@ if [ -n "$RESULTS" ]; then
+   exit 1;
+ fi
+ 
+-echo "Analyzing frontend_server..."
++echo "Analyzing flutter_frontend_server..."
+ RESULTS=`dartanalyzer                                                          \
+-  --packages=flutter/frontend_server/.packages                                 \
++  --packages=flutter/flutter_frontend_server/.packages                                 \
+   --options flutter/analysis_options.yaml                                      \
+-  flutter/frontend_server                                                      \
++  flutter/flutter_frontend_server                                                      \
+   2>&1                                                                         \
+   | grep -Ev "No issues found!"                                                \
+   | grep -Ev "Analyzing.+frontend_server"`
 diff --git a/frontend_server/.gitignore b/flutter_frontend_server/.gitignore
 similarity index 100%
 rename from frontend_server/.gitignore
@@ -280,3 +325,6 @@
  }
  
  SRC_DIR = os.getcwd()
+-- 
+2.23.0.581.g78d2f28ef7-goog
+
diff --git a/utils/dartdevc/BUILD.gn b/utils/dartdevc/BUILD.gn
index 0621dd1..d54c1ef 100644
--- a/utils/dartdevc/BUILD.gn
+++ b/utils/dartdevc/BUILD.gn
@@ -3,6 +3,7 @@
 # BSD-style license that can be found in the LICENSE file.
 
 import("../../build/dart/dart_action.gni")
+import("../../sdk_args.gni")
 import("../application_snapshot.gni")
 import("../create_timestamp.gni")
 
@@ -35,10 +36,17 @@
   ]
 }
 
+# TODO(#38701) Cleanup after merging the forked SDK into mainline.
+if (use_nnbd) {
+  sdk_root = "../../sdk_nnbd"
+} else {
+  sdk_root = "../../sdk"
+}
+
 sdk_lib_files = exec_script("../../tools/list_dart_files.py",
                             [
                               "absolute",
-                              rebase_path("../../sdk/lib"),
+                              rebase_path("$sdk_root/lib"),
                             ],
                             "list lines")
 
@@ -119,7 +127,7 @@
   inputs += exec_script("../../tools/list_dart_files.py",
                         [
                           "absolute",
-                          rebase_path("../../sdk/lib/_internal/js_dev_runtime"),
+                          rebase_path("$sdk_root/lib/_internal/js_dev_runtime"),
                         ],
                         "list lines")
 
@@ -132,9 +140,14 @@
 
   args = [
     rebase_path("../../"),
-    rebase_path("../../sdk/lib/_internal/js_dev_runtime"),
+    rebase_path("$sdk_root/lib/_internal/js_dev_runtime"),
     rebase_path(patched_sdk_dir),
   ]
+
+  # TODO(#38701) Cleanup after merging the forked SDK into mainline.
+  if (use_nnbd) {
+    args += [ "sdk_nnbd" ]
+  }
 }
 
 # Compiles the Dart core libraries and DDC runtime to an analyzer summary and
@@ -228,7 +241,7 @@
 }
 
 create_timestamp_file("dartdevc_sdk_patch_stamp") {
-  path = rebase_path("../../sdk/lib/_internal/js_dev_runtime")
+  path = rebase_path("$sdk_root/lib/_internal/js_dev_runtime")
   output = "$target_gen_dir/dartdevc_sdk_patch_stamp.stamp"
 }
 
@@ -338,7 +351,7 @@
     "--multi-root",
     rebase_path("../../sdk"),
     "--libraries-file",
-    "file:///" + rebase_path("../../sdk/lib/libraries.json"),
+    "file:///" + rebase_path("$sdk_root/lib/libraries.json"),
     "--output",
     rebase_path(sdk_dill),
     "--source",
@@ -348,7 +361,7 @@
 
 copy("dartdevc_kernel_sdk_libraries_json") {
   sources = [
-    rebase_path("../../sdk/lib/libraries.json"),
+    rebase_path("$sdk_root/lib/libraries.json"),
   ]
   outputs = [
     sdk_libraries_json,
@@ -389,7 +402,7 @@
     "--multi-root-scheme",
     "org-dartlang-sdk",
     "--multi-root",
-    "file:///" + rebase_path("../../sdk"),
+    "file:///" + rebase_path(sdk_root),
     "--multi-root-output-path",
     rebase_path("$target_gen_dir/../../"),
     "--libraries-file",
diff --git a/utils/dartfix/BUILD.gn b/utils/dartfix/BUILD.gn
new file mode 100644
index 0000000..e804346
--- /dev/null
+++ b/utils/dartfix/BUILD.gn
@@ -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.
+
+import("../application_snapshot.gni")
+
+application_snapshot("dartfix") {
+  main_dart = "../../pkg/dartfix/bin/dartfix.dart"
+  training_args = [ "--help" ]
+}