Version 2.6.0-dev.6.0

Merge commit '9d55bb6ba7c129d08f968982e15ec1547bd78353' into dev
diff --git a/BUILD.gn b/BUILD.gn
index 60d07ff..a0cbb53 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -77,16 +77,18 @@
   ]
 }
 
-group("create_sdk") {
-  public_deps = [
-    "sdk:create_sdk",
-  ]
-}
-
-group("create_sdk_nnbd") {
-  public_deps = [
-    "sdk_nnbd:create_sdk_nnbd",
-  ]
+if (use_nnbd) {
+  group("create_sdk") {
+    public_deps = [
+      "sdk_nnbd:create_sdk",
+    ]
+  }
+} else {
+  group("create_sdk") {
+    public_deps = [
+      "sdk:create_sdk",
+    ]
+  }
 }
 
 group("dart2js") {
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 81f49ec..0280d0b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,58 @@
 
 ### Language
 
+*   [Static extension members][]: A new language feature allowing
+    specially declared static functions to be invoked
+    like instance members on expressions of appropriate static types.
+    Static extension members are declared using a new `extension`
+    declaration. Example:
+    ```dart
+    extension MyFancyList<T> on List<T> {
+      /// Whether this list has an even length.
+      bool get isLengthEven => this.length.isEven;
+
+      /// Whether this list has an odd length.
+      bool get isLengthOdd => !isLengthEven;
+
+      /// List of values computed for each pairs of adjacent elements.
+      ///
+      /// The result always has one element less than this list,
+      /// if this list has any elements.
+      List<R> combinePairs<R>(R Function(T, T) combine) =>
+          [for (int i = 1; i < this.length; i++)
+              combine(this[i - 1], this[i])];
+    }
+    ```
+    Extension declarations cannot declare instance fields or
+    constructors.
+    Extension members can be invoked explicitly,
+    `MyFancyList(intList).isLengthEven)`,
+    or implicitly, `intList.isLengthEven`,
+    where the latter is recognized by `intList` matching the `List<T>`
+    "on" type of the declaration.
+    An extension member cannot be called implicitly on an expression
+    whose static type has a member with the same base-name.
+    In that case, the interface member takes precedence.
+    If multiple extension members apply to the same implicit
+    invocation, the most specific one is used, if there is one such.
+
+    Extensions can be declared on any type, not just interface types.
+    ```dart
+    extension IntCounter on int {
+      /// The numbers from this number to, but not including, [end].
+      Iterable<int> to(int end) sync* {
+        int step = end < this ? -1 : 1;
+        for (int i = this; i != end; i += step) yield i;
+      }
+    }
+
+    extension CurryFunction<R, S, T> on R Function(S, T) {
+      /// Curry a binary function with its first argument.
+      R Function(T) curry(S first) => (T second) => this(first, second);
+    }
+    ```
+    [Static extension members]: https://github.com/dart-lang/language/blob/master/accepted/2.6/static-extension-members/feature-specification.md
+
 *   **Breaking change** [#37985](https://github.com/dart-lang/sdk/issues/37985):
     Inference is changed when using `Null` values in a `FutureOr` context.
     Namely, constraints of the forms similar to `Null` <: `FutureOr<T>` now
@@ -23,21 +75,30 @@
 * Default values of parameters of abstract methods are no longer available
   via `dart:mirrors`.
 
+#### `dart:developer`
+
+* Added optional `parent` paremeter to `TimelineTask` constructors to allow for
+  linking of asynchronous timeline events in the DevTools timeline view.
+
 ### Dart VM
 
+### Dart for the Web
+
+#### Dart Dev Compiler (DDC)
+
+* Kernel DDC will no longer accept non-dill files as summary inputs.
+* Removed support for the deprecated web extension.
+
 ### Tools
 
 #### Pub
 
 #### Linter
 
-The Linter was updated to `0.1.99`, which includes:
+The Linter was updated to `0.1.100`, which includes:
 
-* fixed unsafe casts in `overridden_fields`
-* (internal) migration to the mock SDK in `package:analyzer` for testing
-* fixed empty argument list access in `use_full_hex_values_for_flutter_color_fix`
-* new lint: `prefer_relative_imports`
-* improved messages for `await_only_futures`
+* (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`
 
 ## 2.5.1 - 2019-09-27
 
diff --git a/DEPS b/DEPS
index 3090e38..7f92015 100644
--- a/DEPS
+++ b/DEPS
@@ -99,7 +99,7 @@
   "intl_tag": "0.15.7",
   "jinja2_rev": "2222b31554f03e62600cd7e383376a7c187967a1",
   "json_rpc_2_tag": "2.0.9",
-  "linter_tag": "0.1.99",
+  "linter_tag": "0.1.100",
   "logging_tag": "0.11.3+2",
   "markupsafe_rev": "8f45f5cfa0009d2a70589bcda0349b8cb2b72783",
   "markdown_tag": "2.1.1",
diff --git a/benchmarks/BigIntParsePrint/dart/BigIntParsePrint.dart b/benchmarks/BigIntParsePrint/dart/BigIntParsePrint.dart
new file mode 100644
index 0000000..fe904ee
--- /dev/null
+++ b/benchmarks/BigIntParsePrint/dart/BigIntParsePrint.dart
@@ -0,0 +1,318 @@
+// 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:benchmark_harness/benchmark_harness.dart';
+import 'package:fixnum/fixnum.dart';
+
+import 'native_version_dummy.dart'
+    if (dart.library.js) 'native_version_javascript.dart';
+
+// Benckmark BigInt and Int64 formatting and parsing.
+
+// A global sink that is used in the [check] method ensures that the results are
+// not optimized.
+dynamic sink1, sink2;
+
+void check(bool sink2isEven) {
+  if (sink1.codeUnits.last.isEven != sink2isEven) {
+    throw StateError('Inconsistent $sink1 vs $sink2');
+  }
+}
+
+// These benchmarks measure digit-throughput for parsing and formatting.
+//
+// Each benchmark targets processing [requiredDigits] decimal digits, spread
+// over a list of input values. This makes the benchmarks for different integer
+// lengths roughly comparable.  The number is chosen so that most benchmarks
+// have very close to this number of digits. It corresponds to nine 4096-bit
+// integers.
+const requiredDigits = 11106;
+
+class ParseBigIntBenchmark extends BenchmarkBase {
+  final int bits;
+  final BigInt seed;
+  final List<String> strings = [];
+
+  ParseBigIntBenchmark(String name, this.bits)
+      : seed = (BigInt.one << bits) - BigInt.one,
+        super(name);
+
+  void setup() {
+    BigInt b = seed;
+    int totalLength = 0;
+    while (totalLength < requiredDigits) {
+      if (b.bitLength < bits) {
+        b = seed;
+      }
+      String string = b.toString();
+      strings.add(string);
+      totalLength += string.length;
+      b = b - (b >> 8);
+    }
+  }
+
+  void run() {
+    for (String s in strings) {
+      BigInt b = BigInt.parse(s);
+      sink1 = s;
+      sink2 = b;
+    }
+    check(sink2.isEven);
+  }
+}
+
+int int64UnsignedBitLength(Int64 i) => i.isNegative ? 64 : i.bitLength;
+
+class ParseInt64Benchmark extends BenchmarkBase {
+  final int bits;
+  final Int64 seed;
+  final List<String> strings = [];
+
+  ParseInt64Benchmark(String name, this.bits)
+      : seed = (Int64.ONE << bits) - Int64.ONE,
+        super(name);
+
+  void setup() {
+    Int64 b = seed;
+    int totalLength = 0;
+    while (totalLength < requiredDigits) {
+      if (int64UnsignedBitLength(b) < bits) {
+        b = seed;
+      }
+      String string = b.toStringUnsigned();
+      strings.add(string);
+      totalLength += string.length;
+      b = b - b.shiftRightUnsigned(8);
+    }
+  }
+
+  void run() {
+    for (String s in strings) {
+      Int64 b = Int64.parseInt(s);
+      sink1 = s;
+      sink2 = b;
+    }
+    check(sink2.isEven);
+  }
+}
+
+class ParseJsBigIntBenchmark extends BenchmarkBase {
+  final int bits;
+  final Object seed;
+  final List<String> strings = [];
+
+  ParseJsBigIntBenchmark(String name, this.bits)
+      : seed = nativeBigInt.subtract(
+            nativeBigInt.shiftLeft(
+                nativeBigInt.one, nativeBigInt.fromInt(bits)),
+            nativeBigInt.one),
+        super(name);
+
+  void setup() {
+    Object b = seed;
+    int totalLength = 0;
+    while (totalLength < requiredDigits) {
+      if (nativeBigInt.bitLength(b) < bits) {
+        b = seed;
+      }
+      String string = nativeBigInt.toStringMethod(b);
+      strings.add(string);
+      totalLength += string.length;
+      b = nativeBigInt.subtract(
+          b, nativeBigInt.shiftRight(b, nativeBigInt.eight));
+    }
+  }
+
+  void run() {
+    for (String s in strings) {
+      Object b = nativeBigInt.parse(s);
+      sink1 = s;
+      sink2 = b;
+    }
+    check(nativeBigInt.isEven(sink2));
+  }
+}
+
+class FormatBigIntBenchmark extends BenchmarkBase {
+  final int bits;
+  final BigInt seed;
+  final List<BigInt> values = [];
+
+  FormatBigIntBenchmark(String name, this.bits)
+      : seed = (BigInt.one << bits) - BigInt.one,
+        super(name);
+
+  void setup() {
+    BigInt b = seed;
+    int totalLength = 0;
+    while (totalLength < requiredDigits) {
+      if (b.bitLength < bits) {
+        b = seed;
+      }
+      String string = b.toString();
+      values.add(b - BigInt.one); // We add 'one' back later.
+      totalLength += string.length;
+      b = b - (b >> 8);
+    }
+  }
+
+  void run() {
+    for (BigInt b0 in values) {
+      // Instances might cache `toString()`, so use arithmetic to create a new
+      // instance to try to protect against measuring a cached string.
+      BigInt b = b0 + BigInt.one;
+      String s = b.toString();
+      sink1 = s;
+      sink2 = b;
+    }
+    check(sink2.isEven);
+  }
+}
+
+class FormatInt64Benchmark extends BenchmarkBase {
+  final int bits;
+  final Int64 seed;
+  final List<Int64> values = [];
+
+  FormatInt64Benchmark(String name, this.bits)
+      : seed = (Int64.ONE << bits) - Int64.ONE,
+        super(name);
+
+  void setup() {
+    Int64 b = seed;
+    int totalLength = 0;
+    while (totalLength < requiredDigits) {
+      if (int64UnsignedBitLength(b) < bits) {
+        b = seed;
+      }
+      String string = b.toStringUnsigned();
+      values.add(b - Int64.ONE);
+      totalLength += string.length;
+      b = b - b.shiftRightUnsigned(8);
+    }
+  }
+
+  void run() {
+    for (Int64 b0 in values) {
+      // Instances might cache `toString()`, so use arithmetic to create a new
+      // instance to try to protect against measuring a cached string.
+      Int64 b = b0 + Int64.ONE;
+      String s = b.toStringUnsigned();
+      sink1 = s;
+      sink2 = b;
+    }
+    check(sink2.isEven);
+  }
+}
+
+class FormatJsBigIntBenchmark extends BenchmarkBase {
+  final int bits;
+  final Object seed;
+  final List<Object> values = [];
+
+  FormatJsBigIntBenchmark(String name, this.bits)
+      : seed = nativeBigInt.subtract(
+            nativeBigInt.shiftLeft(
+                nativeBigInt.one, nativeBigInt.fromInt(bits)),
+            nativeBigInt.one),
+        super(name);
+
+  void setup() {
+    final one = nativeBigInt.one;
+    Object b = seed;
+    int totalLength = 0;
+    while (totalLength < requiredDigits) {
+      if (nativeBigInt.bitLength(b) < bits) {
+        b = seed;
+      }
+      String string = nativeBigInt.toStringMethod(b);
+      values.add(nativeBigInt.subtract(b, one)); // We add 'one' back later.
+      totalLength += string.length;
+      b = nativeBigInt.subtract(
+          b, nativeBigInt.shiftRight(b, nativeBigInt.eight));
+    }
+  }
+
+  void run() {
+    final one = nativeBigInt.one;
+    for (Object b0 in values) {
+      // Instances might cache `toString()`, so use arithmetic to create a new
+      // instance to try to protect against measuring a cached string.
+      Object b = nativeBigInt.add(b0, one);
+      String s = nativeBigInt.toStringMethod(b);
+      sink1 = s;
+      sink2 = b;
+    }
+    check(nativeBigInt.isEven(sink2));
+  }
+}
+
+/// [DummyBenchmark] instantly returns a fixed 'slow' result.
+class DummyBenchmark extends BenchmarkBase {
+  DummyBenchmark(String name) : super(name);
+  double measure() => 2000 * 1000 * 1.0; // A rate of one run per 2s.
+}
+
+/// Create [ParseJsBigIntBenchmark], or a dummy benchmark if JavaScript BigInt
+/// is not available.  This is to satisfy Golem's constraint that group
+/// benchmarks always produce results for the same set of series.
+BenchmarkBase Function() selectParseNativeBigIntBenchmark(
+    String name, int bits) {
+  return nativeBigInt.enabled
+      ? () => ParseJsBigIntBenchmark(name, bits)
+      : () => DummyBenchmark(name);
+}
+
+/// Create [FormatJsBigIntBenchmark], or a dummy benchmark if JavaScript BigInt
+/// is not available.  This is to satisfy Golem's constraint that group
+/// benchmarks always produce results for the same set of series.
+BenchmarkBase Function() selectFormatNativeBigIntBenchmark(
+    String name, int bits) {
+  return nativeBigInt.enabled
+      ? () => FormatJsBigIntBenchmark(name, bits)
+      : () => DummyBenchmark(name);
+}
+
+main() {
+  final benchmarks = [
+    () => ParseInt64Benchmark('Int64.parse.0009.bits', 9),
+    () => ParseInt64Benchmark('Int64.parse.0032.bits', 32),
+    () => ParseInt64Benchmark('Int64.parse.0064.bits', 64),
+    () => ParseBigIntBenchmark('BigInt.parse.0009.bits', 9),
+    () => ParseBigIntBenchmark('BigInt.parse.0032.bits', 32),
+    () => ParseBigIntBenchmark('BigInt.parse.0064.bits', 64),
+    () => ParseBigIntBenchmark('BigInt.parse.0256.bits', 256),
+    () => ParseBigIntBenchmark('BigInt.parse.1024.bits', 1024),
+    () => ParseBigIntBenchmark('BigInt.parse.4096.bits', 4096),
+    selectParseNativeBigIntBenchmark('JsBigInt.parse.0009.bits', 9),
+    selectParseNativeBigIntBenchmark('JsBigInt.parse.0032.bits', 32),
+    selectParseNativeBigIntBenchmark('JsBigInt.parse.0064.bits', 64),
+    selectParseNativeBigIntBenchmark('JsBigInt.parse.0256.bits', 256),
+    selectParseNativeBigIntBenchmark('JsBigInt.parse.1024.bits', 1024),
+    selectParseNativeBigIntBenchmark('JsBigInt.parse.4096.bits', 4096),
+    () => FormatInt64Benchmark('Int64.toString.0009.bits', 9),
+    () => FormatInt64Benchmark('Int64.toString.0032.bits', 32),
+    () => FormatInt64Benchmark('Int64.toString.0064.bits', 64),
+    () => FormatBigIntBenchmark('BigInt.toString.0009.bits', 9),
+    () => FormatBigIntBenchmark('BigInt.toString.0032.bits', 32),
+    () => FormatBigIntBenchmark('BigInt.toString.0064.bits', 64),
+    () => FormatBigIntBenchmark('BigInt.toString.0256.bits', 256),
+    () => FormatBigIntBenchmark('BigInt.toString.1024.bits', 1024),
+    () => FormatBigIntBenchmark('BigInt.toString.4096.bits', 4096),
+    selectFormatNativeBigIntBenchmark('JsBigInt.toString.0009.bits', 9),
+    selectFormatNativeBigIntBenchmark('JsBigInt.toString.0032.bits', 32),
+    selectFormatNativeBigIntBenchmark('JsBigInt.toString.0064.bits', 64),
+    selectFormatNativeBigIntBenchmark('JsBigInt.toString.0256.bits', 256),
+    selectFormatNativeBigIntBenchmark('JsBigInt.toString.1024.bits', 1024),
+    selectFormatNativeBigIntBenchmark('JsBigInt.toString.4096.bits', 4096),
+  ];
+
+  // Warm up all benchmarks to ensure consistent behavious of shared code.
+  benchmarks.forEach((bm) => bm()
+    ..setup()
+    ..run()
+    ..run());
+
+  benchmarks.forEach((bm) => bm().report());
+}
diff --git a/benchmarks/BigIntParsePrint/dart/native_version.dart b/benchmarks/BigIntParsePrint/dart/native_version.dart
new file mode 100644
index 0000000..cfc64fa
--- /dev/null
+++ b/benchmarks/BigIntParsePrint/dart/native_version.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.
+
+abstract class NativeBigIntMethods {
+  bool get enabled;
+
+  Object parse(String string);
+  String toStringMethod(Object value);
+
+  Object fromInt(int i);
+
+  Object get one;
+  Object get eight;
+
+  int bitLength(Object value);
+  bool isEven(Object value);
+
+  Object add(Object left, Object right);
+  Object shiftLeft(Object value, Object count);
+  Object shiftRight(Object value, Object count);
+  Object subtract(Object left, Object right);
+}
diff --git a/benchmarks/BigIntParsePrint/dart/native_version_dummy.dart b/benchmarks/BigIntParsePrint/dart/native_version_dummy.dart
new file mode 100644
index 0000000..42013f0
--- /dev/null
+++ b/benchmarks/BigIntParsePrint/dart/native_version_dummy.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 'native_version.dart';
+
+const NativeBigIntMethods nativeBigInt = _DummyMethods();
+
+class _DummyMethods implements NativeBigIntMethods {
+  const _DummyMethods();
+
+  bool get enabled => false;
+
+  static Object bad(String message) {
+    throw UnimplementedError(message);
+  }
+
+  Object parse(String string) => bad('parse');
+  String toStringMethod(Object value) => bad('toStringMethod');
+
+  Object fromInt(int i) => bad('fromInt');
+
+  Object get one => bad('one');
+  Object get eight => bad('eight');
+
+  int bitLength(Object value) => bad('bitLength');
+  bool isEven(Object value) => bad('isEven');
+
+  Object add(Object left, Object right) => bad('add');
+  Object shiftLeft(Object value, Object count) => bad('shiftLeft');
+  Object shiftRight(Object value, Object count) => bad('shiftRight');
+  Object subtract(Object left, Object right) => bad('subtract');
+}
diff --git a/benchmarks/BigIntParsePrint/dart/native_version_javascript.dart b/benchmarks/BigIntParsePrint/dart/native_version_javascript.dart
new file mode 100644
index 0000000..89f3e9d
--- /dev/null
+++ b/benchmarks/BigIntParsePrint/dart/native_version_javascript.dart
@@ -0,0 +1,110 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'native_version.dart';
+import 'package:js/js.dart';
+
+const NativeBigIntMethods nativeBigInt = _Methods();
+
+@JS('eval')
+external Object _eval(String s);
+
+@JS('bigint_parse')
+external Object _parse(String s);
+
+@JS('bigint_toString')
+external String _toStringMethod(Object o);
+
+@JS('bigint_bitLength')
+external int _bitLength(Object o);
+
+@JS('bigint_isEven')
+external bool _isEven(Object o);
+
+@JS('bigint_add')
+external Object _add(Object left, Object right);
+
+@JS('bigint_shiftLeft')
+external Object _shiftLeft(Object o, Object i);
+
+@JS('bigint_shiftRight')
+external Object _shiftRight(Object o, Object i);
+
+@JS('bigint_subtract')
+external Object _subtract(Object left, Object right);
+
+@JS('bigint_fromInt')
+external Object _fromInt(int i);
+
+class _Methods implements NativeBigIntMethods {
+  static bool _initialized = false;
+  static bool _enabled = false;
+
+  const _Methods();
+
+  bool get enabled {
+    if (!_initialized) {
+      _initialize();
+    }
+    return _enabled;
+  }
+
+  void _initialize() {
+    try {
+      _setup();
+      _enabled = true;
+    } catch (e) {
+      // We get here if the JavaScript implementation does not have BigInt (or
+      // run in a stand-alone JavaScript implementation without the right
+      // 'preamble').
+      //
+      // Print so we can see what failed.
+      print(e);
+    }
+  }
+
+  static Object bad(String message) {
+    throw UnimplementedError(message);
+  }
+
+  Object parse(String string) => _parse(string);
+
+  String toStringMethod(Object value) => _toStringMethod(value);
+
+  Object fromInt(int i) => _fromInt(i);
+
+  Object get one => _one;
+
+  Object get eight => _eight;
+
+  int bitLength(Object value) => _bitLength(value);
+
+  bool isEven(Object value) => _isEven(value);
+
+  Object add(Object left, Object right) => _add(left, right);
+  Object shiftLeft(Object value, Object count) => _shiftLeft(value, count);
+  Object shiftRight(Object value, Object count) => _shiftRight(value, count);
+  Object subtract(Object left, Object right) => _subtract(left, right);
+}
+
+void _setup() {
+  _one = _eval('1n'); // Throws if JavaScript does not have BigInt.
+  _eight = _eval('8n');
+
+  _eval('self.bigint_parse = function parse(s) { return BigInt(s); }');
+  _eval('self.bigint_toString = function toString(b) { return b.toString(); }');
+  _eval('self.bigint_add = function add(a, b) { return a + b; }');
+  _eval('self.bigint_shiftLeft = function shl(v, i) { return v << i; }');
+  _eval('self.bigint_shiftRight = function shr(v, i) { return v >> i; }');
+  _eval('self.bigint_subtract = function subtract(a, b) { return a - b; }');
+  _eval('self.bigint_fromInt = function fromInt(i) { return BigInt(i); }');
+
+  _eval('self.bigint_bitLength = function bitLength(b) {'
+      'return b == 0 ? 0 : (b < 0 ? ~b : b).toString(2).length;'
+      '}');
+  _eval('self.bigint_isEven = function isEven(b) { return (b & 1n) == 0n; }');
+}
+
+Object _one;
+Object _eight;
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 950e06f..576a7a9 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
@@ -75,6 +75,83 @@
 
   /// Return details for a fix built from the given [edge], or `null` if the
   /// edge does not have an origin.
+  String _baseDescriptionForOrigin(AstNode node) {
+    if (node is DefaultFormalParameter) {
+      Expression defaultValue = node.defaultValue;
+      if (defaultValue == null) {
+        return "This parameter has an implicit default value of 'null'";
+      } else if (defaultValue is NullLiteral) {
+        return "This parameter has an explicit default value of 'null'";
+      }
+      return "This parameter has a nullable default value";
+    } else if (node is FieldFormalParameter) {
+      AstNode parent = node.parent;
+      if (parent is DefaultFormalParameter) {
+        Expression defaultValue = parent.defaultValue;
+        if (defaultValue == null) {
+          return "This field is initialized by an optional field formal "
+              "parameter that has an implicit default value of 'null'";
+        } else if (defaultValue is NullLiteral) {
+          return "This field is initialized by an optional field formal "
+              "parameter that has an explicit default value of 'null'";
+        }
+        return "This field is initialized by an optional field formal "
+            "parameter that has a nullable default value";
+      }
+      return "This field is initialized by a field formal parameter and a "
+          "nullable value is passed as an argument";
+    }
+    AstNode parent = node.parent;
+    if (parent is ArgumentList) {
+      if (node is NullLiteral) {
+        return "An explicit 'null' is passed as an argument";
+      }
+      return "A nullable value is explicitly passed as an argument";
+    }
+
+    /// If the [node] is the return expression for a function body, return the
+    /// function body. Otherwise return `null`.
+    AstNode findFunctionBody() {
+      if (parent is ExpressionFunctionBody) {
+        return parent;
+      } else if (parent is ReturnStatement &&
+          parent.parent?.parent is BlockFunctionBody) {
+        return parent.parent.parent;
+      }
+      return null;
+    }
+
+    AstNode functionBody = findFunctionBody();
+    if (functionBody != null) {
+      AstNode function = functionBody.parent;
+      if (function is MethodDeclaration) {
+        if (function.isGetter) {
+          return "This getter returns a nullable value";
+        }
+        return "This method returns a nullable value";
+      }
+      return "This function returns a nullable value";
+    } else if (parent is VariableDeclaration) {
+      AstNode grandparent = parent.parent?.parent;
+      if (grandparent is FieldDeclaration) {
+        if (node is NullLiteral) {
+          return "This field is initialized to null";
+        }
+        return "This field is initialized to a nullable value";
+      }
+      if (node is NullLiteral) {
+        return "This variable is initialized to null";
+      }
+      return "This variable is initialized to a nullable value";
+    }
+    if (node is NullLiteral) {
+      return "An explicit 'null' is assigned";
+    }
+    return "A nullable value is assigned";
+  }
+
+  /// Return details for a fix built from the given [edge], or `null` if the
+  /// edge does not have an origin.
   String _buildDescriptionForDestination(AstNode node) {
     // Other found types:
     // - ConstructorDeclaration
@@ -85,24 +162,12 @@
     }
   }
 
-  /// Return details for a fix built from the given [edge], or `null` if the
-  /// edge does not have an origin.
-  String _buildDescriptionForOrigin(AstNode node) {
-    String /*!*/ description;
-    if (node.parent is ArgumentList) {
-      if (node is NullLiteral) {
-        description = "An explicit 'null' is passed as an argument";
-      } else {
-        description = "A nullable value is explicitly passed as an argument";
-      }
-    } else {
-      if (node is NullLiteral) {
-        description = "An explicit 'null' is assigned";
-      } else {
-        description = "A nullable value is assigned";
-      }
-    }
-    if (_inTestCode(node)) {
+  /// Return a description of the given [origin].
+  String _buildDescriptionForOrigin(AstNode origin) {
+    String description = _baseDescriptionForOrigin(origin);
+    if (_inTestCode(origin)) {
+      // TODO(brianwilkerson) Don't add this if the graph node with which the
+      //  origin is associated is also in test code.
       description += " in test code";
     }
     return description;
@@ -123,6 +188,9 @@
               //  the superclass.
               details.add(RegionDetail(_buildDescriptionForOrigin(origin.node),
                   _targetForNode(origin.source.fullName, origin.node)));
+            } else {
+              details.add(
+                  RegionDetail('upstream edge with no origin ($edge)', null));
             }
           }
         }
@@ -133,6 +201,8 @@
           details.add(RegionDetail(
               _buildDescriptionForDestination(nodeInfo.astNode),
               _targetForNode(nodeInfo.filePath, nodeInfo.astNode)));
+        } else {
+          details.add(RegionDetail('node with no info ($destination)', null));
         }
       } else {
         throw UnimplementedError(
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 7e3812a..b243b6f 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
@@ -104,7 +104,7 @@
 }
 
 .target {
-  background-color: #FFFFFF;
+  background-color: #FFFF99;
   position: relative;
   visibility: visible;
 }
@@ -180,6 +180,8 @@
 
   /// 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),
@@ -314,6 +316,11 @@
 
   /// Return the URL that will navigate to the given [target].
   String _uriForTarget(NavigationTarget target) {
+    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);
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 3c3870b..4299d23 100644
--- a/pkg/analysis_server/lib/src/services/correction/base_processor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/base_processor.dart
@@ -24,6 +24,7 @@
 import 'package:analyzer_plugin/utilities/change_builder/change_workspace.dart';
 import 'package:analyzer_plugin/utilities/range_factory.dart';
 import 'package:meta/meta.dart';
+import 'package:path/path.dart' as path;
 
 /// Base class for common processor functionality.
 abstract class BaseProcessor {
@@ -98,71 +99,112 @@
       return null;
     }
 
-    var constructorInvocation;
-    if (type.isDartCoreBool) {
-      constructorInvocation = 'DiagnosticsProperty<bool>';
-    } else if (type.isDartCoreInt) {
-      constructorInvocation = 'IntProperty';
+    var constructorName;
+    var typeArgs;
+
+    if (type.isDartCoreInt) {
+      constructorName = 'IntProperty';
     } else if (type.isDartCoreDouble) {
-      constructorInvocation = 'DoubleProperty';
+      constructorName = 'DoubleProperty';
     } else if (type.isDartCoreString) {
-      constructorInvocation = 'StringProperty';
+      constructorName = 'StringProperty';
     } else if (isEnum(type)) {
-      constructorInvocation = 'EnumProperty';
+      constructorName = 'EnumProperty';
+    } else if (isIterable(type)) {
+      constructorName = 'IterableProperty';
+      typeArgs = (type as InterfaceType).typeArguments;
+    } else if (flutter.isColor(type)) {
+      constructorName = 'ColorProperty';
+    } else if (flutter.isMatrix4(type)) {
+      constructorName = 'TransformProperty';
+    } else {
+      constructorName = 'DiagnosticsProperty';
+      if (!type.isDynamic) {
+        typeArgs = [type];
+      }
     }
 
-    // todo (pq): migrate type string generation to within change and use DartEditBuilder.writeType
-
-    if (constructorInvocation == null) {
-      return null;
+    void writePropertyReference(
+      DartEditBuilder builder, {
+      @required String prefix,
+      @required String builderName,
+    }) {
+      builder.write("$prefix$builderName.add($constructorName");
+      if (typeArgs != null) {
+        builder.write('<');
+        builder.writeTypes(typeArgs);
+        builder.write('>');
+      }
+      builder.writeln("('${name.name}', ${name.name}));");
     }
 
-    ClassDeclaration classDeclaration =
-        parent.thisOrAncestorOfType<ClassDeclaration>();
+    final classDeclaration = parent.thisOrAncestorOfType<ClassDeclaration>();
     final debugFillProperties =
         classDeclaration.getMethod('debugFillProperties');
-    if (debugFillProperties != null) {
-      final body = debugFillProperties.body;
-      if (body is BlockFunctionBody) {
-        BlockFunctionBody functionBody = body;
+    if (debugFillProperties == null) {
+      final insertOffset =
+          utils.prepareNewMethodLocation(classDeclaration).offset;
+      final changeBuilder = _newDartChangeBuilder();
+      await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+        builder.addInsertion(utils.getLineNext(insertOffset),
+            (DartEditBuilder builder) {
+          final declPrefix =
+              utils.getLinePrefix(classDeclaration.offset) + utils.getIndent(1);
+          final bodyPrefix = declPrefix + utils.getIndent(1);
 
-        var offset;
-        var prefix;
-        if (functionBody.block.statements.isEmpty) {
-          offset = functionBody.block.leftBracket.offset;
-          prefix = utils.getLinePrefix(offset) + utils.getIndent(1);
-        } else {
-          offset = functionBody.block.statements.last.endToken.offset;
-          prefix = utils.getLinePrefix(offset);
-        }
+          builder.writeln('$declPrefix@override');
+          builder.writeln(
+              '${declPrefix}void debugFillProperties(DiagnosticPropertiesBuilder properties) {');
+          builder
+              .writeln('${bodyPrefix}super.debugFillProperties(properties);');
+          writePropertyReference(builder,
+              prefix: bodyPrefix, builderName: 'properties');
+          builder.writeln('$declPrefix}');
+        });
+      });
+      return changeBuilder;
+    }
 
-        var parameters = debugFillProperties.parameters.parameters;
-        var propertiesBuilderName;
-        for (var parameter in parameters) {
-          if (parameter is SimpleFormalParameter) {
-            final type = parameter.type;
-            if (type is TypeName) {
-              if (type.name.name == 'DiagnosticPropertiesBuilder') {
-                propertiesBuilderName = parameter.identifier.name;
-                break;
-              }
+    final body = debugFillProperties.body;
+    if (body is BlockFunctionBody) {
+      BlockFunctionBody functionBody = body;
+
+      var offset;
+      var prefix;
+      if (functionBody.block.statements.isEmpty) {
+        offset = functionBody.block.leftBracket.offset;
+        prefix = utils.getLinePrefix(offset) + utils.getIndent(1);
+      } else {
+        offset = functionBody.block.statements.last.endToken.offset;
+        prefix = utils.getLinePrefix(offset);
+      }
+
+      var parameters = debugFillProperties.parameters.parameters;
+      var propertiesBuilderName;
+      for (var parameter in parameters) {
+        if (parameter is SimpleFormalParameter) {
+          final type = parameter.type;
+          if (type is TypeName) {
+            if (type.name.name == 'DiagnosticPropertiesBuilder') {
+              propertiesBuilderName = parameter.identifier.name;
+              break;
             }
           }
         }
-        if (propertiesBuilderName == null) {
-          return null;
-        }
-
-        final changeBuilder = _newDartChangeBuilder();
-        await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
-          builder.addInsertion(utils.getLineNext(offset),
-              (DartEditBuilder builder) {
-            builder.write(
-                "$prefix$propertiesBuilderName.add($constructorInvocation('${name.name}', ${name.name}));$eol");
-          });
-        });
-        return changeBuilder;
       }
+      if (propertiesBuilderName == null) {
+        return null;
+      }
+
+      final changeBuilder = _newDartChangeBuilder();
+      await changeBuilder.addFileEdit(file, (DartFileEditBuilder builder) {
+        builder.addInsertion(utils.getLineNext(offset),
+            (DartEditBuilder builder) {
+          writePropertyReference(builder,
+              prefix: prefix, builderName: propertiesBuilderName);
+        });
+      });
+      return changeBuilder;
     }
 
     return null;
@@ -922,6 +964,65 @@
     return null;
   }
 
+  Future<ChangeBuilder> createBuilder_convertToRelativeImport() async {
+    var node = this.node;
+    if (node is StringLiteral) {
+      node = node.parent;
+    }
+    if (node is! ImportDirective) {
+      return null;
+    }
+
+    ImportDirective importDirective = node;
+
+    // Ignore if invalid URI.
+    if (importDirective.uriSource == null) {
+      return null;
+    }
+
+    // Ignore if the uri is not a package: uri.
+    Uri sourceUri = resolvedResult.uri;
+    if (sourceUri.scheme != 'package') {
+      return null;
+    }
+
+    Uri importUri;
+    try {
+      importUri = Uri.parse(importDirective.uriContent);
+    } on FormatException {
+      return null;
+    }
+
+    // Ignore if import uri is not a package: uri.
+    if (importUri.scheme != 'package') {
+      return null;
+    }
+
+    // Verify that the source's uri and the import uri have the same package
+    // name.
+    List<String> sourceSegments = sourceUri.pathSegments;
+    List<String> importSegments = importUri.pathSegments;
+    if (sourceSegments.isEmpty ||
+        importSegments.isEmpty ||
+        sourceSegments.first != importSegments.first) {
+      return null;
+    }
+
+    final String relativePath = path.relative(
+      importUri.path,
+      from: path.dirname(sourceUri.path),
+    );
+
+    DartChangeBuilder changeBuilder = _newDartChangeBuilder();
+    await changeBuilder.addFileEdit(file, (builder) {
+      builder.addSimpleReplacement(
+        range.node(importDirective.uri).getExpanded(-1),
+        relativePath,
+      );
+    });
+    return changeBuilder;
+  }
+
   Future<ChangeBuilder> createBuilder_inlineAdd() async {
     AstNode node = this.node;
     if (node is! SimpleIdentifier || node.parent is! MethodInvocation) {
@@ -1213,6 +1314,28 @@
     return element is ClassElement && element.isEnum;
   }
 
+  bool isIterable(DartType type) {
+    if (type is! InterfaceType) {
+      return false;
+    }
+
+    ClassElement element = type.element;
+
+    bool isExactIterable(ClassElement element) {
+      return element?.name == 'Iterable' && element.library.isDartCore;
+    }
+
+    if (isExactIterable(element)) {
+      return true;
+    }
+    for (InterfaceType type in element.allSupertypes) {
+      if (isExactIterable(type.element)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   @protected
   bool setupCompute() {
     final locator = NodeLocator(selectionOffset, selectionEnd);
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 6a005f2..e209c70 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -205,6 +205,8 @@
       const FixKind('CONVERT_TO_NULL_AWARE', 50, "Convert to use '?.'");
   static const CONVERT_TO_PACKAGE_IMPORT = const FixKind(
       'CONVERT_TO_PACKAGE_IMPORT', 50, "Convert to 'package:' import");
+  static const CONVERT_TO_RELATIVE_IMPORT = const FixKind(
+      'CONVERT_TO_RELATIVE_IMPORT', 50, "Convert to relative import");
   static const CONVERT_TO_SINGLE_QUOTED_STRING = const FixKind(
       'CONVERT_TO_SINGLE_QUOTED_STRING', 50, "Convert to single quoted string");
   static const CONVERT_TO_SPREAD =
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 801408f..c5d2376 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -693,6 +693,9 @@
       if (name == LintNames.prefer_null_aware_operators) {
         await _addFix_convertToNullAware();
       }
+      if (name == LintNames.prefer_relative_imports) {
+        await _addFix_convertToRelativeImport();
+      }
       if (name == LintNames.prefer_single_quotes) {
         await _addFix_convertSingleQuotes();
       }
@@ -1528,6 +1531,11 @@
     _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_TO_PACKAGE_IMPORT);
   }
 
+  Future<void> _addFix_convertToRelativeImport() async {
+    final changeBuilder = await createBuilder_convertToRelativeImport();
+    _addFixFromBuilder(changeBuilder, DartFixKind.CONVERT_TO_RELATIVE_IMPORT);
+  }
+
   Future<void> _addFix_createClass() async {
     Element prefixElement = null;
     String name = null;
diff --git a/pkg/analysis_server/lib/src/services/linter/lint_names.dart b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
index fbd3a46..343f30c 100644
--- a/pkg/analysis_server/lib/src/services/linter/lint_names.dart
+++ b/pkg/analysis_server/lib/src/services/linter/lint_names.dart
@@ -50,6 +50,7 @@
   static const String prefer_is_not_empty = 'prefer_is_not_empty';
   static const String prefer_null_aware_operators =
       'prefer_null_aware_operators';
+  static const String prefer_relative_imports = 'prefer_relative_imports';
   static const String prefer_single_quotes = 'prefer_single_quotes';
   static const String prefer_spread_collections = 'prefer_spread_collections';
   static const String slash_for_doc_comments = 'slash_for_doc_comments';
diff --git a/pkg/analysis_server/lib/src/utilities/flutter.dart b/pkg/analysis_server/lib/src/utilities/flutter.dart
index eccd264..288d4fb 100644
--- a/pkg/analysis_server/lib/src/utilities/flutter.dart
+++ b/pkg/analysis_server/lib/src/utilities/flutter.dart
@@ -362,6 +362,36 @@
   bool isChildrenArgument(Expression argument) =>
       argument is NamedExpression && argument.name.label.name == 'children';
 
+  /**
+   * Return `true` if the given [type] is the dart.ui class `Color`, or its
+   * subtype.
+   */
+  bool isColor(DartType type) {
+    if (type is! InterfaceType) {
+      return false;
+    }
+
+    bool isColorElement(ClassElement element) {
+      if (element == null) {
+        return false;
+      }
+
+      bool isExactColor(ClassElement element) =>
+          element?.name == 'Color' && element.library.name == 'dart.ui';
+      if (isExactColor(element)) {
+        return true;
+      }
+      for (var type in element.allSupertypes) {
+        if (isExactColor(type.element)) {
+          return true;
+        }
+      }
+      return false;
+    }
+
+    return isColorElement(type.element);
+  }
+
   /// Return `true` if the [element] is the Flutter class `Alignment`.
   bool isExactAlignment(ClassElement element) {
     return _isExactWidget(element, 'Alignment', _uriAlignment);
@@ -480,6 +510,37 @@
         isWidgetType(type.typeArguments[0]);
   }
 
+  /**
+   * Return `true` if the given [type] is the dart.ui class `Color`, or its
+   * subtype.
+   */
+  bool isMatrix4(DartType type) {
+    if (type is! InterfaceType) {
+      return false;
+    }
+
+    bool isMatrix4Element(ClassElement element) {
+      if (element == null) {
+        return false;
+      }
+
+      bool isExactMatrix4(ClassElement element) =>
+          element?.name == 'Matrix4' &&
+          element.library.name == 'vector_math_64';
+      if (isExactMatrix4(element)) {
+        return true;
+      }
+      for (var type in element.allSupertypes) {
+        if (isExactMatrix4(type.element)) {
+          return true;
+        }
+      }
+      return false;
+    }
+
+    return isMatrix4Element(type.element);
+  }
+
   /// Return `true` if the given [element] has the Flutter class `State` as
   /// a superclass.
   bool isState(ClassElement element) {
diff --git a/pkg/analysis_server/test/abstract_context.dart b/pkg/analysis_server/test/abstract_context.dart
index 6ec7193..b1e3156 100644
--- a/pkg/analysis_server/test/abstract_context.dart
+++ b/pkg/analysis_server/test/abstract_context.dart
@@ -116,6 +116,11 @@
     createAnalysisContexts();
   }
 
+  void addVectorMathPackage() {
+    Folder libFolder = MockPackages.instance.addVectorMath(resourceProvider);
+    addTestPackageDependency('vector_math', libFolder.parent.path);
+  }
+
   /// Create all analysis contexts in `/home`.
   void createAnalysisContexts() {
     _analysisContextCollection = AnalysisContextCollectionImpl(
diff --git a/pkg/analysis_server/test/domain_edit_dartfix_test.dart b/pkg/analysis_server/test/domain_edit_dartfix_test.dart
index c3fa84f..8360a1f 100644
--- a/pkg/analysis_server/test/domain_edit_dartfix_test.dart
+++ b/pkg/analysis_server/test/domain_edit_dartfix_test.dart
@@ -190,7 +190,9 @@
 ''');
   }
 
+  @failingTest
   test_dartfix_nonNullable() async {
+    // Failing because this contains a side-cast from Null to int.
     createAnalysisOptionsFile(experiments: ['non-nullable']);
     addTestFile('''
 int f(int i) => 0;
diff --git a/pkg/analysis_server/test/mock_packages/vector_math/lib/matrix4.dart b/pkg/analysis_server/test/mock_packages/vector_math/lib/matrix4.dart
new file mode 100644
index 0000000..ed4d3cb
--- /dev/null
+++ b/pkg/analysis_server/test/mock_packages/vector_math/lib/matrix4.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2015, Google Inc. Please see the AUTHORS file for 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 vector_math_64;
+
+/// 4D Matrix.
+/// Values are stored in column major order.
+class Matrix4 {}
diff --git a/pkg/analysis_server/test/mock_packages/vector_math/lib/vector_math_64.dart b/pkg/analysis_server/test/mock_packages/vector_math/lib/vector_math_64.dart
new file mode 100644
index 0000000..54cfbf0
--- /dev/null
+++ b/pkg/analysis_server/test/mock_packages/vector_math/lib/vector_math_64.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2015, Google Inc. Please see the AUTHORS file for details.
+// All rights reserved. Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/// A library containing different type of vector operations for use in games,
+/// simulations, or rendering.
+///
+/// The library contains Vector classes ([Vector2], [Vector3] and [Vector4]),
+/// Matrices classes ([Matrix2], [Matrix3] and [Matrix4]) and collision
+/// detection related classes ([Aabb2], [Aabb3], [Frustum], [Obb3], [Plane],
+/// [Quad], [Ray], [Sphere] and [Triangle]).
+///
+/// In addition some utilities are available as color operations (See [Colors]
+/// class), noise generators ([SimplexNoise]) and common OpenGL operations
+/// (like [makeViewMatrix], [makePerspectiveMatrix], or [pickRay]).
+///
+/// There is also a [vector_math_64_64] library available that uses double
+/// precision (64-bit) instead of single precision (32-bit) floating point
+/// numbers for storage.
+library vector_math_64;
+
+part 'matrix4.dart';
diff --git a/pkg/analysis_server/test/mock_packages/vector_math/pubspec.yaml b/pkg/analysis_server/test/mock_packages/vector_math/pubspec.yaml
new file mode 100644
index 0000000..b69249b
--- /dev/null
+++ b/pkg/analysis_server/test/mock_packages/vector_math/pubspec.yaml
@@ -0,0 +1 @@
+name: vector_math
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 d349e0d..e9f2f1b 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
@@ -9,6 +9,7 @@
 import 'package:analysis_server/src/edit/nnbd_migration/instrumentation_listener.dart';
 import 'package:analysis_server/src/edit/nnbd_migration/migration_info.dart';
 import 'package:analyzer/dart/analysis/results.dart';
+import 'package:meta/meta.dart';
 import 'package:nnbd_migration/nnbd_migration.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -27,6 +28,24 @@
   /// not yet completed.
   List<UnitInfo> infos;
 
+  /// 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.
+  void assertRegion(
+      {@required RegionInfo region,
+      int offset,
+      int length,
+      List<String> details}) {
+    if (offset != null) {
+      expect(region.offset, offset);
+      expect(region.length, length ?? 1);
+    }
+    if (details != null) {
+      expect(region.details.map((detail) => detail.description),
+          unorderedEquals(details));
+    }
+  }
+
   /// Use the InfoBuilder to build information. The information will be stored
   /// in [infos].
   Future<void> buildInfo() async {
@@ -53,7 +72,123 @@
     infos = await builder.explainMigration();
   }
 
-  test_parameter_nullable_fromInvocation() async {
+  test_field_fieldFormalInitializer_optional() async {
+    addTestFile('''
+class A {
+  int _f;
+  A([this._f]);
+}
+''');
+    await buildInfo();
+    expect(infos, hasLength(1));
+    UnitInfo unit = infos[0];
+    expect(unit.path, testFile);
+    expect(unit.content, '''
+class A {
+  int? _f;
+  A([this._f]);
+}
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(1));
+    assertRegion(region: regions[0], offset: 15, details: [
+      "This field is initialized by an optional field formal parameter that "
+          "has an implicit default value of 'null'"
+    ]);
+  }
+
+  test_field_fieldFormalInitializer_required() async {
+    addTestFile('''
+class A {
+  int _f;
+  A(this._f);
+}
+void g() {
+  A(null);
+}
+''');
+    await buildInfo();
+    expect(infos, hasLength(1));
+    UnitInfo unit = infos[0];
+    expect(unit.path, testFile);
+    expect(unit.content, '''
+class A {
+  int? _f;
+  A(this._f);
+}
+void g() {
+  A(null);
+}
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(1));
+    // TODO(brianwilkerson) It would be nice if the target for the region could
+    //  be the argument rather than the field formal parameter.
+    assertRegion(region: regions[0], offset: 15, details: [
+      "This field is initialized by a field formal parameter and a nullable "
+          "value is passed as an argument"
+    ]);
+  }
+
+  test_field_initializer() async {
+    addTestFile('''
+class A {
+  int _f = null;
+  int _f2 = _f;
+}
+''');
+    await buildInfo();
+    expect(infos, hasLength(1));
+    UnitInfo unit = infos[0];
+    expect(unit.path, testFile);
+    expect(unit.content, '''
+class A {
+  int? _f = null;
+  int? _f2 = _f;
+}
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(2));
+    assertRegion(
+        region: regions[0],
+        offset: 15,
+        details: ["This field is initialized to null"]);
+    assertRegion(
+        region: regions[1],
+        offset: 33,
+        details: ["This field is initialized to a nullable value"]);
+  }
+
+  test_localVariable() async {
+    addTestFile('''
+void f() {
+  int _v1 = null;
+  int _v2 = _v1;
+}
+''');
+    await buildInfo();
+    expect(infos, hasLength(1));
+    UnitInfo unit = infos[0];
+    expect(unit.path, testFile);
+    expect(unit.content, '''
+void f() {
+  int? _v1 = null;
+  int? _v2 = _v1;
+}
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(2));
+    assertRegion(
+        region: regions[0],
+        offset: 16,
+        details: ["This variable is initialized to null"]);
+    assertRegion(
+        region: regions[1],
+        offset: 35,
+        details: ["This variable is initialized to a nullable value"]);
+  }
+
+  test_parameter_fromInvocation_explicit() async {
     addTestFile('''
 void f(String s) {}
 void g() {
@@ -72,14 +207,42 @@
 ''');
     List<RegionInfo> regions = unit.regions;
     expect(regions, hasLength(1));
-    RegionInfo region = regions[0];
-    expect(region.offset, 13);
-    expect(region.length, 1);
-    List<RegionDetail> details = region.details;
-    expect(details, hasLength(1));
+    assertRegion(
+        region: regions[0],
+        offset: 13,
+        details: ["An explicit 'null' is passed as an argument"]);
   }
 
-  test_parameter_nullable_fromOverriden() async {
+  @failingTest
+  test_parameter_fromInvocation_implicit() async {
+    // Failing because the upstream edge ("always -(hard)-> type(13)")
+    // associated with the reason (a _NullabilityNodeSimple) had a `null` origin
+    // when the listener's `graphEdge` method was called.
+    addTestFile('''
+void f(String s) {}
+void g(p) {
+  f(p);
+}
+''');
+    await buildInfo();
+    expect(infos, hasLength(1));
+    UnitInfo unit = infos[0];
+    expect(unit.path, testFile);
+    expect(unit.content, '''
+void f(String? s) {}
+void g(p) {
+  f(p);
+}
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(1));
+    assertRegion(
+        region: regions[0],
+        offset: 13,
+        details: ["A nullable value is explicitly passed as an argument"]);
+  }
+
+  test_parameter_fromOverriden() async {
     addTestFile('''
 class A {
   void m(p) {}
@@ -102,10 +265,207 @@
 ''');
     List<RegionInfo> regions = unit.regions;
     expect(regions, hasLength(1));
-    RegionInfo region = regions[0];
-    expect(region.offset, 62);
-    expect(region.length, 1);
-    List<RegionDetail> details = region.details;
-    expect(details, hasLength(1));
+    // TODO(brianwilkerson) The detail should read something like
+    //  "The overridden method accepts a nullable type"
+    assertRegion(
+        region: regions[0],
+        offset: 62,
+        details: ["A nullable value is assigned"]);
+  }
+
+  @failingTest
+  test_parameter_optional_explicitDefault_null() async {
+    // Failing because we appear to never get an origin when the upstream node
+    // for an edge is 'always'.
+    addTestFile('''
+void f({String s = null}) {}
+''');
+    await buildInfo();
+    expect(infos, hasLength(1));
+    UnitInfo unit = infos[0];
+    expect(unit.path, testFile);
+    expect(unit.content, '''
+void f({String? s = null}) {}
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(1));
+    assertRegion(
+        region: regions[0],
+        offset: 14,
+        details: ["This parameter has an explicit default value of 'null'"]);
+  }
+
+  @failingTest
+  test_parameter_optional_explicitDefault_nullable() async {
+    // Failing because we appear to never get an origin when the upstream node
+    // for an edge is 'always'.
+    addTestFile('''
+const sd = null;
+void f({String s = sd}) {}
+''');
+    await buildInfo();
+    expect(infos, hasLength(1));
+    UnitInfo unit = infos[0];
+    expect(unit.path, testFile);
+    expect(unit.content, '''
+const sd = null;
+void f({String? s = sd}) {}
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(1));
+    assertRegion(
+        region: regions[0],
+        offset: 31,
+        details: ["This parameter has an explicit default value of 'null'"]);
+  }
+
+  test_parameter_optional_implicitDefault_named() async {
+    addTestFile('''
+void f({String s}) {}
+''');
+    await buildInfo();
+    expect(infos, hasLength(1));
+    UnitInfo unit = infos[0];
+    expect(unit.path, testFile);
+    expect(unit.content, '''
+void f({String? s}) {}
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(1));
+    assertRegion(
+        region: regions[0],
+        offset: 14,
+        details: ["This parameter has an implicit default value of 'null'"]);
+  }
+
+  test_parameter_optional_implicitDefault_positional() async {
+    addTestFile('''
+void f([String s]) {}
+''');
+    await buildInfo();
+    expect(infos, hasLength(1));
+    UnitInfo unit = infos[0];
+    expect(unit.path, testFile);
+    expect(unit.content, '''
+void f([String? s]) {}
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(1));
+    assertRegion(
+        region: regions[0],
+        offset: 14,
+        details: ["This parameter has an implicit default value of 'null'"]);
+  }
+
+  test_returnType_function_expression() async {
+    addTestFile('''
+int _f = null;
+int f() => _f;
+''');
+    await buildInfo();
+    expect(infos, hasLength(1));
+    UnitInfo unit = infos[0];
+    expect(unit.path, testFile);
+    expect(unit.content, '''
+int? _f = null;
+int? f() => _f;
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(2));
+    assertRegion(
+        region: regions[0],
+        offset: 3,
+        details: ["This variable is initialized to null"]);
+    assertRegion(
+        region: regions[1],
+        offset: 19,
+        details: ["This function returns a nullable value"]);
+  }
+
+  test_returnType_getter_block() async {
+    addTestFile('''
+class A {
+  int _f = null;
+  int get f {
+    return _f;
+  }
+}
+''');
+    await buildInfo();
+    expect(infos, hasLength(1));
+    UnitInfo unit = infos[0];
+    expect(unit.path, testFile);
+    expect(unit.content, '''
+class A {
+  int? _f = null;
+  int? get f {
+    return _f;
+  }
+}
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(2));
+    assertRegion(
+        region: regions[0],
+        offset: 15,
+        details: ["This field is initialized to null"]);
+    assertRegion(
+        region: regions[1],
+        offset: 33,
+        details: ["This getter returns a nullable value"]);
+  }
+
+  test_returnType_getter_expression() async {
+    addTestFile('''
+class A {
+  int _f = null;
+  int get f => _f;
+}
+''');
+    await buildInfo();
+    expect(infos, hasLength(1));
+    UnitInfo unit = infos[0];
+    expect(unit.path, testFile);
+    expect(unit.content, '''
+class A {
+  int? _f = null;
+  int? get f => _f;
+}
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(2));
+    assertRegion(
+        region: regions[0],
+        offset: 15,
+        details: ["This field is initialized to null"]);
+    assertRegion(
+        region: regions[1],
+        offset: 33,
+        details: ["This getter returns a nullable value"]);
+  }
+
+  test_topLevelVariable() async {
+    addTestFile('''
+int _f = null;
+int _f2 = _f;
+''');
+    await buildInfo();
+    expect(infos, hasLength(1));
+    UnitInfo unit = infos[0];
+    expect(unit.path, testFile);
+    expect(unit.content, '''
+int? _f = null;
+int? _f2 = _f;
+''');
+    List<RegionInfo> regions = unit.regions;
+    expect(regions, hasLength(2));
+    assertRegion(
+        region: regions[0],
+        offset: 3,
+        details: ["This variable is initialized to null"]);
+    assertRegion(
+        region: regions[1],
+        offset: 19,
+        details: ["This variable is initialized to a nullable value"]);
   }
 }
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 13f5ab3..4cf256e 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
@@ -115,6 +115,31 @@
 ''');
   }
 
+  test_colorField_debugFillProperties() async {
+    addFlutterPackage();
+    await resolveTestUnit('''
+import 'package:flutter/material.dart';
+class A extends Widget {
+  Color /*LINT*/field;
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+  }
+}
+''');
+    await assertHasFix('''
+import 'package:flutter/material.dart';
+class A extends Widget {
+  Color /*LINT*/field;
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+    properties.add(ColorProperty('field', field));
+  }
+}
+''');
+  }
+
   test_doubleField_debugFillProperties() async {
     await resolveTestUnit('''
 class A extends Widget {
@@ -137,6 +162,28 @@
 ''');
   }
 
+  test_dynamicField_debugFillProperties() async {
+    await resolveTestUnit('''
+class A extends Widget {
+  dynamic /*LINT*/field;
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+  }
+}
+''');
+    await assertHasFix('''
+class A extends Widget {
+  dynamic /*LINT*/field;
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+    properties.add(DiagnosticsProperty('field', field));
+  }
+}
+''');
+  }
+
   test_enumField_debugFillProperties() async {
     await resolveTestUnit('''
 enum foo {bar}
@@ -183,6 +230,97 @@
 ''');
   }
 
+  test_iterableField_debugFillProperties() async {
+    await resolveTestUnit('''
+class A extends Widget {
+  Iterable<String> /*LINT*/field;
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+  }
+}
+''');
+    await assertHasFix('''
+class A extends Widget {
+  Iterable<String> /*LINT*/field;
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+    properties.add(IterableProperty<String>('field', field));
+  }
+}
+''');
+  }
+
+  test_listField_debugFillProperties() async {
+    await resolveTestUnit('''
+class A extends Widget {
+  List<List<String>> /*LINT*/field;
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+  }
+}
+''');
+    await assertHasFix('''
+class A extends Widget {
+  List<List<String>> /*LINT*/field;
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+    properties.add(IterableProperty<List<String>>('field', field));
+  }
+}
+''');
+  }
+
+  test_matrix4Field_debugFillProperties() async {
+    addVectorMathPackage();
+    await resolveTestUnit('''
+import 'package:vector_math/vector_math_64.dart';
+class A extends Widget {
+  Matrix4 /*LINT*/field;
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+  }
+}
+''');
+    await assertHasFix('''
+import 'package:vector_math/vector_math_64.dart';
+class A extends Widget {
+  Matrix4 /*LINT*/field;
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+    properties.add(TransformProperty('field', field));
+  }
+}
+''');
+  }
+
+  test_objectField_debugFillProperties() async {
+    await resolveTestUnit('''
+class A extends Widget {
+  Object /*LINT*/field;
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+  }
+}
+''');
+    await assertHasFix('''
+class A extends Widget {
+  Object /*LINT*/field;
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+    properties.add(DiagnosticsProperty<Object>('field', field));
+  }
+}
+''');
+  }
+
   test_stringField_debugFillProperties() async {
     await resolveTestUnit('''
 class A extends Widget {
@@ -205,10 +343,24 @@
 ''');
   }
 
-  // todo (pq): tests for no debugFillProperties method
+  test_stringField_noDebugFillProperties() async {
+    await resolveTestUnit('''
+class A extends Widget {
+  String /*LINT*/field;
+}
+''');
+    await assertHasFix('''
+class A extends Widget {
+  String /*LINT*/field;
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+    properties.add(StringProperty('field', field));
+  }
+}
+''');
+  }
+
   // todo (pq): consider a test for a body w/ no CR
-  // todo (pq): support for ColorProperty -- for Color
-  // todo (pq): support for IterableProperty -- any iterable
-  // todo (pq): support for TransformProperty -- Matrix4
   // todo (pq): support for DiagnosticsProperty for any T that doesn't match one of the other cases
 }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/convert_to_relative_import_test.dart b/pkg/analysis_server/test/src/services/correction/fix/convert_to_relative_import_test.dart
new file mode 100644
index 0000000..bfe46a0
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/convert_to_relative_import_test.dart
@@ -0,0 +1,96 @@
+// 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/fix.dart';
+import 'package:analysis_server/src/services/linter/lint_names.dart';
+import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'fix_processor.dart';
+
+main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(ConvertToRelativeImportTest);
+  });
+}
+
+@reflectiveTest
+class ConvertToRelativeImportTest extends FixProcessorLintTest {
+  @override
+  FixKind get kind => DartFixKind.CONVERT_TO_RELATIVE_IMPORT;
+
+  @override
+  String get lintCode => LintNames.prefer_relative_imports;
+
+  test_relativeImport() async {
+    addSource('/home/test/lib/foo.dart', '');
+    testFile = convertPath('/home/test/lib/src/test.dart');
+    await resolveTestUnit('''
+import /*LINT*/'package:test/foo.dart';
+''');
+
+    await assertHasFix('''
+import /*LINT*/'../foo.dart';
+''');
+  }
+
+  test_relativeImportSameDirectory() async {
+    addSource('/home/test/lib/foo.dart', '');
+    testFile = convertPath('/home/test/lib/bar.dart');
+    await resolveTestUnit('''
+import /*LINT*/'package:test/foo.dart';
+''');
+
+    await assertHasFix('''
+import /*LINT*/'foo.dart';
+''');
+  }
+
+  test_relativeImportSubDirectory() async {
+    addSource('/home/test/lib/baz/foo.dart', '');
+    testFile = convertPath('/home/test/lib/test.dart');
+    await resolveTestUnit('''
+import /*LINT*/'package:test/baz/foo.dart';
+''');
+
+    await assertHasFix('''
+import /*LINT*/'baz/foo.dart';
+''');
+  }
+
+  test_relativeImportRespectQuoteStyle() async {
+    addSource('/home/test/lib/foo.dart', '');
+    testFile = convertPath('/home/test/lib/bar.dart');
+    await resolveTestUnit('''
+import /*LINT*/"package:test/foo.dart";
+''');
+
+    await assertHasFix('''
+import /*LINT*/"foo.dart";
+''');
+  }
+
+  test_relativeImportGarbledUri() async {
+    addSource('/home/test/lib/foo.dart', '');
+    testFile = convertPath('/home/test/lib/bar.dart');
+    await resolveTestUnit('''
+import /*LINT*/'package:test/foo';
+''');
+
+    await assertHasFix('''
+import /*LINT*/'foo';
+''');
+  }
+
+  // Validate we don't get a fix with imports referencing different packages.
+  test_relativeImportDifferentPackages() async {
+    addSource('/home/test1/lib/foo.dart', '');
+    testFile = convertPath('/home/test2/lib/bar.dart');
+    await resolveTestUnit('''
+import /*LINT*/'package:test1/foo.dart';
+''');
+
+    await assertNoFix();
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
index 3c6ba74..43df03a 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/test_all.dart
@@ -46,6 +46,7 @@
 import 'convert_to_named_arguments_test.dart' as convert_to_named_arguments;
 import 'convert_to_null_aware_test.dart' as convert_to_null_aware;
 import 'convert_to_package_import_test.dart' as convert_to_package_import;
+import 'convert_to_relative_import_test.dart' as convert_to_relative_import;
 import 'convert_to_single_quoted_string_test.dart'
     as convert_to_single_quoted_string;
 import 'convert_to_spread_test.dart' as convert_to_spread;
@@ -172,6 +173,7 @@
     convert_to_named_arguments.main();
     convert_to_null_aware.main();
     convert_to_package_import.main();
+    convert_to_relative_import.main();
     convert_to_single_quoted_string.main();
     convert_to_spread.main();
     create_class.main();
diff --git a/pkg/analysis_server/test/src/utilities/mock_packages.dart b/pkg/analysis_server/test/src/utilities/mock_packages.dart
index 81647c3..0629c20 100644
--- a/pkg/analysis_server/test/src/utilities/mock_packages.dart
+++ b/pkg/analysis_server/test/src/utilities/mock_packages.dart
@@ -34,6 +34,11 @@
     return packageFolder.getChildAssumingFolder('lib');
   }
 
+  Folder addVectorMath(MemoryResourceProvider provider) {
+    var packageFolder = _addFiles(provider, 'vector_math');
+    return packageFolder.getChildAssumingFolder('lib');
+  }
+
   /// Add files of the given [packageName] to the [provider].
   Folder _addFiles(MemoryResourceProvider provider, String packageName) {
     var packagesPath = provider.convertPath('/packages');
diff --git a/pkg/analyzer/lib/dart/ast/ast.dart b/pkg/analyzer/lib/dart/ast/ast.dart
index 6bfb473..5e4ff56 100644
--- a/pkg/analyzer/lib/dart/ast/ast.dart
+++ b/pkg/analyzer/lib/dart/ast/ast.dart
@@ -1234,7 +1234,7 @@
   /// directive in a comment at the top of the file.
   ///
   /// Might be `null` if, for example, this [CompilationUnit] has been
-  /// resynthesized from a summary,
+  /// resynthesized from a summary.
   FeatureSet get featureSet;
 
   /// Return the line information for this compilation unit.
diff --git a/pkg/analyzer/lib/error/error.dart b/pkg/analyzer/lib/error/error.dart
index 72e7f56..9219d3e 100644
--- a/pkg/analyzer/lib/error/error.dart
+++ b/pkg/analyzer/lib/error/error.dart
@@ -325,6 +325,8 @@
   HintCode.DEPRECATED_FUNCTION_CLASS_DECLARATION,
   HintCode.DEPRECATED_MEMBER_USE,
   HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE,
+  HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE_WITH_MESSAGE,
+  HintCode.DEPRECATED_MEMBER_USE_WITH_MESSAGE,
   HintCode.DEPRECATED_MIXIN_FUNCTION,
   HintCode.DIVISION_OPTIMIZATION,
   HintCode.DUPLICATE_IMPORT,
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index c87f158..6bdbfa6 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -6353,11 +6353,27 @@
       function?.parameters ?? const <ParameterElement>[];
 
   @override
-  DartType get returnType => function?.returnType;
+  DartType get returnType {
+    if (function == null) {
+      // TODO(scheglov) The context is null in unit tests.
+      return context?.typeProvider?.dynamicType;
+    }
+    return function?.returnType;
+  }
 
   @override
   FunctionType get type {
-    _type ??= new FunctionTypeImpl.forTypedef(this);
+    _type ??= FunctionTypeImpl.synthetic(
+      returnType,
+      typeParameters,
+      parameters,
+      element: this,
+      typeArguments: typeParameters.map((e) {
+        return e.instantiate(
+          nullabilitySuffix: NullabilitySuffix.star,
+        );
+      }).toList(),
+    );
     return _type;
   }
 
@@ -6435,11 +6451,14 @@
     @required List<DartType> typeArguments,
     @required NullabilitySuffix nullabilitySuffix,
   }) {
-    // TODO(scheglov) Replace with strict function type.
-    return FunctionTypeImpl.forTypedef(
-      this,
+    return FunctionTypeImpl.synthetic(
+      returnType,
+      typeParameters,
+      parameters,
+      element: this,
+      typeArguments: typeArguments,
       nullabilitySuffix: nullabilitySuffix,
-    ).instantiate(typeArguments);
+    );
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index c1339c9..8ceb5c9 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -39,18 +39,6 @@
 }
 
 /**
- * Type of callbacks used by [DeferredFunctionTypeImpl].
- */
-typedef FunctionTypedElement FunctionTypedElementComputer();
-
-/**
- * Computer of type arguments which is used to delay computing of type
- * arguments until they are requested, instead of at the [ParameterizedType]
- * creation time.
- */
-typedef List<DartType> TypeArgumentsComputer();
-
-/**
  * A [Type] that represents the type 'bottom'.
  */
 class BottomTypeImpl extends TypeImpl {
@@ -329,54 +317,6 @@
 }
 
 /**
- * The type of a function, method, constructor, getter, or setter that has been
- * resynthesized from a summary.  The actual underlying element won't be
- * constructed until it's needed.
- */
-class DeferredFunctionTypeImpl extends _FunctionTypeImplLazy {
-  /**
-   * Callback which should be invoked when the element associated with this
-   * function type is needed.
-   *
-   * Once the callback has been invoked, it is set to `null` to reduce GC
-   * pressure.
-   */
-  FunctionTypedElementComputer _computeElement;
-
-  /**
-   * If [_computeElement] has been called, the value it returned.  Otherwise
-   * `null`.
-   */
-  FunctionTypedElement _computedElement;
-
-  DeferredFunctionTypeImpl(this._computeElement, String name,
-      List<DartType> typeArguments, bool isInstantiated,
-      {NullabilitySuffix nullabilitySuffix = NullabilitySuffix.star,
-      FunctionTypedElement computedElement})
-      : _computedElement = computedElement,
-        super._(null, name, null, typeArguments, null, null, isInstantiated,
-            nullabilitySuffix: nullabilitySuffix);
-
-  @override
-  FunctionTypedElement get element {
-    if (_computeElement != null) {
-      _computedElement = _computeElement();
-      _computeElement = null;
-    }
-    return _computedElement;
-  }
-
-  @override
-  TypeImpl withNullability(NullabilitySuffix nullabilitySuffix) {
-    if (this.nullabilitySuffix == nullabilitySuffix) return this;
-    return DeferredFunctionTypeImpl(
-        _computeElement, name, typeArguments, isInstantiated,
-        computedElement: _computedElement,
-        nullabilitySuffix: nullabilitySuffix);
-  }
-}
-
-/**
  * The [Type] representing the type `dynamic`.
  */
 class DynamicTypeImpl extends TypeImpl {
@@ -479,82 +419,6 @@
         nullabilitySuffix: nullabilitySuffix);
   }
 
-  /**
-   * Initialize a newly created function type to be declared by the given
-   * [element].
-   *
-   * Note: this constructor mishandles generics.
-   * See https://github.com/dart-lang/sdk/issues/34657.
-   */
-  factory FunctionTypeImpl.forTypedef(FunctionTypeAliasElement element,
-      {NullabilitySuffix nullabilitySuffix = NullabilitySuffix.star}) {
-    return new _FunctionTypeImplLazy._(
-        element, element?.name, null, null, null, null, false,
-        nullabilitySuffix: nullabilitySuffix);
-  }
-
-  /**
-   * Initialize a newly created function type that is semantically the same as
-   * [original], but which has been syntactically renamed with fresh type
-   * parameters at its outer binding site (if any).
-   *
-   * If type formals is empty, this returns the original unless [force] is set
-   * to [true].
-   */
-  factory FunctionTypeImpl.fresh(FunctionType original,
-      {bool force = false,
-      NullabilitySuffix nullabilitySuffix = NullabilitySuffix.star}) {
-    // We build up a substitution for the type parameters,
-    // {variablesFresh/variables} then apply it.
-
-    var originalFormals = original.typeFormals;
-    var formalCount = originalFormals.length;
-    if (formalCount == 0 && !force) return original;
-
-    // Allocate fresh type variables
-    var typeVars = <TypeParameterElement>[];
-    var freshTypeVars = <DartType>[];
-    var freshVarElements = <TypeParameterElement>[];
-    for (int i = 0; i < formalCount; i++) {
-      var typeParamElement = originalFormals[i];
-
-      var freshElement =
-          new TypeParameterElementImpl.synthetic(typeParamElement.name);
-      var freshTypeVar = new TypeParameterTypeImpl(freshElement);
-
-      typeVars.add(typeParamElement);
-      freshTypeVars.add(freshTypeVar);
-      freshVarElements.add(freshElement);
-    }
-
-    // Simultaneous substitution to rename the bounds
-    for (int i = 0; i < formalCount; i++) {
-      var typeParamElement = originalFormals[i];
-      var bound = typeParamElement.bound;
-      if (bound != null) {
-        var freshElement = freshVarElements[i] as TypeParameterElementImpl;
-        freshElement.bound = Substitution.fromPairs(typeVars, freshTypeVars)
-            .substituteType(bound);
-      }
-    }
-
-    // Instantiate the original type with the fresh type variables
-    // (replacing the old type variables)
-    var newType = original.instantiate(freshTypeVars);
-
-    // Build a synthetic element for the type, binding the fresh type parameters
-    var name = original.name ?? "";
-    var element = original.element;
-    var function = new FunctionElementImpl(name, -1);
-    function.enclosingElement = element?.enclosingElement;
-    function.isSynthetic = true;
-    function.returnType = newType.returnType;
-    function.typeParameters = freshVarElements;
-    function.shareParameters(newType.parameters);
-    return function.type =
-        new FunctionTypeImpl(function, nullabilitySuffix: nullabilitySuffix);
-  }
-
   /// Creates a function type that's not associated with any element in the
   /// element tree.
   factory FunctionTypeImpl.synthetic(DartType returnType,
@@ -1245,12 +1109,6 @@
   List<DartType> _typeArguments = const <DartType>[];
 
   /**
-   * If not `null` and [_typeArguments] is `null`, the actual type arguments
-   * should be computed (once) using this function.
-   */
-  TypeArgumentsComputer _typeArgumentsComputer;
-
-  /**
    * The set of typedefs which should not be expanded when exploring this type,
    * to avoid creating infinite types in response to self-referential typedefs.
    */
@@ -1283,18 +1141,6 @@
       {this.prunedTypedefs, this.nullabilitySuffix = NullabilitySuffix.star})
       : super(element, element.displayName);
 
-  /**
-   * Initialize a newly created type to be declared by the given [element],
-   * with the given [name] and [typeArguments].
-   */
-  InterfaceTypeImpl.elementWithNameAndArgs(
-      ClassElement element, String name, this._typeArgumentsComputer,
-      {this.nullabilitySuffix = NullabilitySuffix.star})
-      : prunedTypedefs = null,
-        super(element, name) {
-    _typeArguments = null;
-  }
-
   InterfaceTypeImpl.explicit(ClassElement element, List<DartType> typeArguments,
       {this.nullabilitySuffix = NullabilitySuffix.star})
       : prunedTypedefs = null,
@@ -1302,15 +1148,6 @@
         super(element, element.displayName);
 
   /**
-   * Initialize a newly created type to have the given [name]. This constructor
-   * should only be used in cases where there is no declaration of the type.
-   */
-  InterfaceTypeImpl.named(String name,
-      {this.nullabilitySuffix = NullabilitySuffix.star})
-      : prunedTypedefs = null,
-        super(null, name);
-
-  /**
    * Private constructor.
    */
   InterfaceTypeImpl._(Element element, String name, this.prunedTypedefs,
@@ -1320,7 +1157,6 @@
   InterfaceTypeImpl._withNullability(InterfaceTypeImpl original,
       {this.nullabilitySuffix = NullabilitySuffix.star})
       : _typeArguments = original._typeArguments,
-        _typeArgumentsComputer = original._typeArgumentsComputer,
         prunedTypedefs = original.prunedTypedefs,
         super(original.element, original.name);
 
@@ -1571,10 +1407,6 @@
 
   @override
   List<DartType> get typeArguments {
-    if (_typeArguments == null) {
-      _typeArguments = _typeArgumentsComputer();
-      _typeArgumentsComputer = null;
-    }
     return _typeArguments;
   }
 
@@ -1583,7 +1415,6 @@
    */
   void set typeArguments(List<DartType> typeArguments) {
     _typeArguments = typeArguments;
-    _typeArgumentsComputer = null;
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/error/hint_codes.dart b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
index 281fecf..58cfd25 100644
--- a/pkg/analyzer/lib/src/dart/error/hint_codes.dart
+++ b/pkg/analyzer/lib/src/dart/error/hint_codes.dart
@@ -133,6 +133,34 @@
           hasPublishedDocs: true);
 
   /**
+   * Parameters:
+   * 0: the name of the member
+   * 1: message details
+   */
+  static const HintCode DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE_WITH_MESSAGE =
+      const HintCodeWithUniqueName(
+          'DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE',
+          'HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE_WITH_MESSAGE',
+          "'{0}' is deprecated and shouldn't be used. {1}.",
+          correction: "Try replacing the use of the deprecated member with the "
+              "replacement.",
+          hasPublishedDocs: true);
+
+  /**
+   * Parameters:
+   * 0: the name of the member
+   * 1: message details
+   */
+  static const HintCode DEPRECATED_MEMBER_USE_WITH_MESSAGE =
+      const HintCodeWithUniqueName(
+          'DEPRECATED_MEMBER_USE',
+          'HintCode.DEPRECATED_MEMBER_USE_WITH_MESSAGE',
+          "'{0}' is deprecated and shouldn't be used. {1}.",
+          correction: "Try replacing the use of the deprecated member with the "
+              "replacement.",
+          hasPublishedDocs: true);
+
+  /**
    * `Function` should not be mixed in anymore.
    */
   static const HintCode DEPRECATED_MIXIN_FUNCTION = const HintCode(
@@ -785,7 +813,7 @@
   // #### Common fixes
   //
   // If you don't need to support older versions of the SDK, then you can
-  // ncrease the SDK constraint to allow the expression to be used:
+  // increase the SDK constraint to allow the expression to be used:
   //
   // ```yaml
   // environment:
@@ -1584,3 +1612,13 @@
   @override
   ErrorType get type => ErrorType.HINT;
 }
+
+class HintCodeWithUniqueName extends HintCode {
+  @override
+  final String uniqueName;
+
+  const HintCodeWithUniqueName(String name, this.uniqueName, String message,
+      {String correction, bool hasPublishedDocs})
+      : super(name, message,
+            correction: correction, hasPublishedDocs: hasPublishedDocs);
+}
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 ab50520..23d0a05 100644
--- a/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
+++ b/pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
@@ -225,8 +225,8 @@
 
 const ParserErrorCode _EQUALITY_CANNOT_BE_EQUALITY_OPERAND = const ParserErrorCode(
     'EQUALITY_CANNOT_BE_EQUALITY_OPERAND',
-    r"An equality expression can't be an operand of another equality expression.",
-    correction: "Try re-writing the expression.");
+    r"A comparison expression can't be an operand of another comparison expression.",
+    correction: "Try putting parentheses around one of the comparisons.");
 
 const ParserErrorCode _EXPECTED_BODY = const ParserErrorCode(
     'EXPECTED_BODY', r"A #string must have a body, even if it is empty.",
@@ -293,7 +293,8 @@
 
 const ParserErrorCode _EXTERNAL_FIELD = const ParserErrorCode(
     'EXTERNAL_FIELD', r"Fields can't be declared to be 'external'.",
-    correction: "Try removing the keyword 'external'.");
+    correction:
+        "Try removing the keyword 'external', or replacing the field by an external getter and/or setter.");
 
 const ParserErrorCode _EXTERNAL_METHOD_WITH_BODY = const ParserErrorCode(
     'EXTERNAL_METHOD_WITH_BODY',
@@ -314,7 +315,7 @@
 
 const ParserErrorCode _FIELD_INITIALIZED_OUTSIDE_DECLARING_CLASS =
     const ParserErrorCode('FIELD_INITIALIZED_OUTSIDE_DECLARING_CLASS',
-        r"A field can only be initialized in it's declaring class",
+        r"A field can only be initialized in its declaring class",
         correction:
             "Try passing a value into the superclass constructor, or moving the initialization into the constructor body.");
 
@@ -405,7 +406,7 @@
 
 const ParserErrorCode _MISSING_ASSIGNABLE_SELECTOR = const ParserErrorCode(
     'MISSING_ASSIGNABLE_SELECTOR',
-    r"Missing selector such as '.<identifier>' or '[0]'.",
+    r"Missing selector such as '.identifier' or '[0]'.",
     correction: "Try adding a selector.");
 
 const ParserErrorCode _MISSING_ASSIGNMENT_IN_INITIALIZER =
@@ -441,7 +442,8 @@
 const ParserErrorCode _MISSING_PREFIX_IN_DEFERRED_IMPORT =
     const ParserErrorCode('MISSING_PREFIX_IN_DEFERRED_IMPORT',
         r"Deferred imports should have a prefix.",
-        correction: "Try adding a prefix to the import.");
+        correction:
+            "Try adding a prefix to the import by adding an 'as' clause.");
 
 const ParserErrorCode _MISSING_STATEMENT =
     const ParserErrorCode('MISSING_STATEMENT', r"Expected a statement.");
diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart
index 5b76714..9b42e29 100644
--- a/pkg/analyzer/lib/src/fasta/ast_builder.dart
+++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart
@@ -642,12 +642,251 @@
   }
 
   @override
+  void endClassConstructor(Token getOrSet, Token beginToken, Token beginParam,
+      Token beginInitializers, Token endToken) {
+    assert(getOrSet == null ||
+        optional('get', getOrSet) ||
+        optional('set', getOrSet));
+    debugEvent("ClassConstructor");
+
+    var bodyObject = pop();
+    List<ConstructorInitializer> initializers = pop() ?? const [];
+    Token separator = pop();
+    FormalParameterList parameters = pop();
+    TypeParameterList typeParameters = pop();
+    var name = pop();
+    TypeAnnotation returnType = pop();
+    _Modifiers modifiers = pop();
+    List<Annotation> metadata = pop();
+    Comment comment = _findComment(metadata, beginToken);
+
+    assert(parameters != null || optional('get', getOrSet));
+
+    ConstructorName redirectedConstructor;
+    FunctionBody body;
+    if (bodyObject is FunctionBody) {
+      body = bodyObject;
+    } else if (bodyObject is _RedirectingFactoryBody) {
+      separator = bodyObject.equalToken;
+      redirectedConstructor = bodyObject.constructorName;
+      body = ast.emptyFunctionBody(endToken);
+    } else {
+      unhandled("${bodyObject.runtimeType}", "bodyObject",
+          beginToken.charOffset, uri);
+    }
+
+    SimpleIdentifier prefixOrName;
+    Token period;
+    SimpleIdentifier nameOrNull;
+    if (name is SimpleIdentifier) {
+      prefixOrName = name;
+    } else if (name is PrefixedIdentifier) {
+      prefixOrName = name.prefix;
+      period = name.period;
+      nameOrNull = name.identifier;
+    } else {
+      throw new UnimplementedError(
+          'name is an instance of ${name.runtimeType} in endClassConstructor');
+    }
+
+    if (typeParameters != null) {
+      // Outline builder also reports this error message.
+      handleRecoverableError(messageConstructorWithTypeParameters,
+          typeParameters.beginToken, typeParameters.endToken);
+    }
+    if (modifiers?.constKeyword != null &&
+        body != null &&
+        (body.length > 1 || body.beginToken?.lexeme != ';')) {
+      // This error is also reported in BodyBuilder.finishFunction
+      Token bodyToken = body.beginToken ?? modifiers.constKeyword;
+      handleRecoverableError(
+          messageConstConstructorWithBody, bodyToken, bodyToken);
+    }
+    if (returnType != null) {
+      // This error is also reported in OutlineBuilder.endMethod
+      handleRecoverableError(messageConstructorWithReturnType,
+          returnType.beginToken, returnType.beginToken);
+    }
+    ConstructorDeclaration constructor = ast.constructorDeclaration(
+        comment,
+        metadata,
+        modifiers?.externalKeyword,
+        modifiers?.finalConstOrVarKeyword,
+        null,
+        // TODO(paulberry): factoryKeyword
+        ast.simpleIdentifier(prefixOrName.token),
+        period,
+        nameOrNull,
+        parameters,
+        separator,
+        initializers,
+        redirectedConstructor,
+        body);
+    currentDeclarationMembers.add(constructor);
+    if (mixinDeclaration != null) {
+      // TODO (danrubel): Report an error if this is a mixin declaration.
+    }
+  }
+
+  @override
   void endClassDeclaration(Token beginToken, Token endToken) {
     debugEvent("ClassDeclaration");
     classDeclaration = null;
   }
 
   @override
+  void endClassFactoryMethod(
+      Token beginToken, Token factoryKeyword, Token endToken) {
+    assert(optional('factory', factoryKeyword));
+    assert(optional(';', endToken) || optional('}', endToken));
+    debugEvent("ClassFactoryMethod");
+
+    FunctionBody body;
+    Token separator;
+    ConstructorName redirectedConstructor;
+    Object bodyObject = pop();
+    if (bodyObject is FunctionBody) {
+      body = bodyObject;
+    } else if (bodyObject is _RedirectingFactoryBody) {
+      separator = bodyObject.equalToken;
+      redirectedConstructor = bodyObject.constructorName;
+      body = ast.emptyFunctionBody(endToken);
+    } else {
+      unhandled("${bodyObject.runtimeType}", "bodyObject",
+          beginToken.charOffset, uri);
+    }
+
+    FormalParameterList parameters = pop();
+    TypeParameterList typeParameters = pop();
+    Object constructorName = pop();
+    _Modifiers modifiers = pop();
+    List<Annotation> metadata = pop();
+    Comment comment = _findComment(metadata, beginToken);
+
+    assert(parameters != null);
+
+    if (typeParameters != null) {
+      // TODO(danrubel): Update OutlineBuilder to report this error message.
+      handleRecoverableError(messageConstructorWithTypeParameters,
+          typeParameters.beginToken, typeParameters.endToken);
+    }
+
+    // Decompose the preliminary ConstructorName into the type name and
+    // the actual constructor name.
+    SimpleIdentifier returnType;
+    Token period;
+    SimpleIdentifier name;
+    Identifier typeName = constructorName;
+    if (typeName is SimpleIdentifier) {
+      returnType = typeName;
+    } else if (typeName is PrefixedIdentifier) {
+      returnType = typeName.prefix;
+      period = typeName.period;
+      name =
+          ast.simpleIdentifier(typeName.identifier.token, isDeclaration: true);
+    }
+
+    currentDeclarationMembers.add(ast.constructorDeclaration(
+        comment,
+        metadata,
+        modifiers?.externalKeyword,
+        modifiers?.finalConstOrVarKeyword,
+        factoryKeyword,
+        ast.simpleIdentifier(returnType.token),
+        period,
+        name,
+        parameters,
+        separator,
+        null,
+        redirectedConstructor,
+        body));
+  }
+
+  @override
+  void endClassFields(Token staticToken, Token covariantToken, Token lateToken,
+      Token varFinalOrConst, int count, Token beginToken, Token semicolon) {
+    assert(optional(';', semicolon));
+    debugEvent("Fields");
+
+    List<VariableDeclaration> variables = popTypedList(count);
+    TypeAnnotation type = pop();
+    var variableList = ast.variableDeclarationList2(
+      lateKeyword: lateToken,
+      keyword: varFinalOrConst,
+      type: type,
+      variables: variables,
+    );
+    Token covariantKeyword = covariantToken;
+    List<Annotation> metadata = pop();
+    Comment comment = _findComment(metadata, beginToken);
+    currentDeclarationMembers.add(ast.fieldDeclaration2(
+        comment: comment,
+        metadata: metadata,
+        covariantKeyword: covariantKeyword,
+        staticKeyword: staticToken,
+        fieldList: variableList,
+        semicolon: semicolon));
+  }
+
+  @override
+  void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
+      Token beginInitializers, Token endToken) {
+    assert(getOrSet == null ||
+        optional('get', getOrSet) ||
+        optional('set', getOrSet));
+    debugEvent("ClassMethod");
+
+    var bodyObject = pop();
+    pop(); // initializers
+    pop(); // separator
+    FormalParameterList parameters = pop();
+    TypeParameterList typeParameters = pop();
+    var name = pop();
+    TypeAnnotation returnType = pop();
+    _Modifiers modifiers = pop();
+    List<Annotation> metadata = pop();
+    Comment comment = _findComment(metadata, beginToken);
+
+    assert(parameters != null || optional('get', getOrSet));
+
+    FunctionBody body;
+    if (bodyObject is FunctionBody) {
+      body = bodyObject;
+    } else if (bodyObject is _RedirectingFactoryBody) {
+      body = ast.emptyFunctionBody(endToken);
+    } else {
+      unhandled("${bodyObject.runtimeType}", "bodyObject",
+          beginToken.charOffset, uri);
+    }
+
+    Token operatorKeyword;
+    SimpleIdentifier nameId;
+    if (name is SimpleIdentifier) {
+      nameId = name;
+    } else if (name is _OperatorName) {
+      operatorKeyword = name.operatorKeyword;
+      nameId = name.name;
+    } else {
+      throw new UnimplementedError(
+          'name is an instance of ${name.runtimeType} in endClassMethod');
+    }
+
+    checkFieldFormalParameters(parameters);
+    currentDeclarationMembers.add(ast.methodDeclaration(
+        comment,
+        metadata,
+        modifiers?.externalKeyword,
+        modifiers?.abstractKeyword ?? modifiers?.staticKeyword,
+        returnType,
+        getOrSet,
+        operatorKeyword,
+        nameId,
+        typeParameters,
+        parameters,
+        body));
+  }
+
+  @override
   void endClassOrMixinBody(DeclarationKind kind, int memberCount,
       Token leftBracket, Token rightBracket) {
     // TODO(danrubel): consider renaming endClassOrMixinBody
@@ -823,6 +1062,25 @@
   }
 
   @override
+  void endExtensionConstructor(Token getOrSet, Token beginToken,
+      Token beginParam, Token beginInitializers, Token endToken) {
+    debugEvent("ExtensionConstructor");
+    // TODO(danrubel) Decide how to handle constructor declarations within
+    // extensions. They are invalid and the parser has already reported an
+    // error at this point. In the future, we should include them in order
+    // to get navigation, search, etc.
+    pop(); // body
+    pop(); // initializers
+    pop(); // separator
+    pop(); // parameters
+    pop(); // typeParameters
+    pop(); // name
+    pop(); // returnType
+    pop(); // modifiers
+    pop(); // metadata
+  }
+
+  @override
   void endExtensionDeclaration(
       Token extensionKeyword, Token onKeyword, Token token) {
     TypeAnnotation type = pop();
@@ -833,81 +1091,6 @@
   }
 
   @override
-  void endClassFactoryMethod(
-      Token beginToken, Token factoryKeyword, Token endToken) {
-    assert(optional('factory', factoryKeyword));
-    assert(optional(';', endToken) || optional('}', endToken));
-    debugEvent("ClassFactoryMethod");
-
-    FunctionBody body;
-    Token separator;
-    ConstructorName redirectedConstructor;
-    Object bodyObject = pop();
-    if (bodyObject is FunctionBody) {
-      body = bodyObject;
-    } else if (bodyObject is _RedirectingFactoryBody) {
-      separator = bodyObject.equalToken;
-      redirectedConstructor = bodyObject.constructorName;
-      body = ast.emptyFunctionBody(endToken);
-    } else {
-      unhandled("${bodyObject.runtimeType}", "bodyObject",
-          beginToken.charOffset, uri);
-    }
-
-    FormalParameterList parameters = pop();
-    TypeParameterList typeParameters = pop();
-    Object constructorName = pop();
-    _Modifiers modifiers = pop();
-    List<Annotation> metadata = pop();
-    Comment comment = _findComment(metadata, beginToken);
-
-    assert(parameters != null);
-
-    if (typeParameters != null) {
-      // TODO(danrubel): Update OutlineBuilder to report this error message.
-      handleRecoverableError(messageConstructorWithTypeParameters,
-          typeParameters.beginToken, typeParameters.endToken);
-    }
-
-    // Decompose the preliminary ConstructorName into the type name and
-    // the actual constructor name.
-    SimpleIdentifier returnType;
-    Token period;
-    SimpleIdentifier name;
-    Identifier typeName = constructorName;
-    if (typeName is SimpleIdentifier) {
-      returnType = typeName;
-    } else if (typeName is PrefixedIdentifier) {
-      returnType = typeName.prefix;
-      period = typeName.period;
-      name =
-          ast.simpleIdentifier(typeName.identifier.token, isDeclaration: true);
-    }
-
-    currentDeclarationMembers.add(ast.constructorDeclaration(
-        comment,
-        metadata,
-        modifiers?.externalKeyword,
-        modifiers?.finalConstOrVarKeyword,
-        factoryKeyword,
-        ast.simpleIdentifier(returnType.token),
-        period,
-        name,
-        parameters,
-        separator,
-        null,
-        redirectedConstructor,
-        body));
-  }
-
-  @override
-  void endMixinFactoryMethod(
-      Token beginToken, Token factoryKeyword, Token endToken) {
-    debugEvent("MixinFactoryMethod");
-    endClassFactoryMethod(beginToken, factoryKeyword, endToken);
-  }
-
-  @override
   void endExtensionFactoryMethod(
       Token beginToken, Token factoryKeyword, Token endToken) {
     assert(optional('factory', factoryKeyword));
@@ -965,48 +1148,6 @@
         body));
   }
 
-  void endFieldInitializer(Token assignment, Token token) {
-    assert(optional('=', assignment));
-    debugEvent("FieldInitializer");
-
-    Expression initializer = pop();
-    SimpleIdentifier name = pop();
-    push(_makeVariableDeclaration(name, assignment, initializer));
-  }
-
-  @override
-  void endClassFields(Token staticToken, Token covariantToken, Token lateToken,
-      Token varFinalOrConst, int count, Token beginToken, Token semicolon) {
-    assert(optional(';', semicolon));
-    debugEvent("Fields");
-
-    List<VariableDeclaration> variables = popTypedList(count);
-    TypeAnnotation type = pop();
-    var variableList = ast.variableDeclarationList2(
-      lateKeyword: lateToken,
-      keyword: varFinalOrConst,
-      type: type,
-      variables: variables,
-    );
-    Token covariantKeyword = covariantToken;
-    List<Annotation> metadata = pop();
-    Comment comment = _findComment(metadata, beginToken);
-    currentDeclarationMembers.add(ast.fieldDeclaration2(
-        comment: comment,
-        metadata: metadata,
-        covariantKeyword: covariantKeyword,
-        staticKeyword: staticToken,
-        fieldList: variableList,
-        semicolon: semicolon));
-  }
-
-  @override
-  void endMixinFields(Token staticToken, Token covariantToken, Token lateToken,
-      Token varFinalOrConst, int count, Token beginToken, Token endToken) {
-    endClassFields(staticToken, covariantToken, lateToken, varFinalOrConst,
-        count, beginToken, endToken);
-  }
-
   @override
   void endExtensionFields(
       Token staticToken,
@@ -1027,6 +1168,23 @@
   }
 
   @override
+  void endExtensionMethod(Token getOrSet, Token beginToken, Token beginParam,
+      Token beginInitializers, Token endToken) {
+    debugEvent("ExtensionMethod");
+    endClassMethod(
+        getOrSet, beginToken, beginParam, beginInitializers, endToken);
+  }
+
+  void endFieldInitializer(Token assignment, Token token) {
+    assert(optional('=', assignment));
+    debugEvent("FieldInitializer");
+
+    Expression initializer = pop();
+    SimpleIdentifier name = pop();
+    push(_makeVariableDeclaration(name, assignment, initializer));
+  }
+
+  @override
   void endForControlFlow(Token token) {
     debugEvent("endForControlFlow");
     var entry = pop();
@@ -1569,165 +1727,6 @@
   }
 
   @override
-  void endClassMethod(Token getOrSet, Token beginToken, Token beginParam,
-      Token beginInitializers, Token endToken) {
-    assert(getOrSet == null ||
-        optional('get', getOrSet) ||
-        optional('set', getOrSet));
-    debugEvent("ClassMethod");
-
-    var bodyObject = pop();
-    pop(); // initializers
-    pop(); // separator
-    FormalParameterList parameters = pop();
-    TypeParameterList typeParameters = pop();
-    var name = pop();
-    TypeAnnotation returnType = pop();
-    _Modifiers modifiers = pop();
-    List<Annotation> metadata = pop();
-    Comment comment = _findComment(metadata, beginToken);
-
-    assert(parameters != null || optional('get', getOrSet));
-
-    FunctionBody body;
-    if (bodyObject is FunctionBody) {
-      body = bodyObject;
-    } else if (bodyObject is _RedirectingFactoryBody) {
-      body = ast.emptyFunctionBody(endToken);
-    } else {
-      unhandled("${bodyObject.runtimeType}", "bodyObject",
-          beginToken.charOffset, uri);
-    }
-
-    Token operatorKeyword;
-    SimpleIdentifier nameId;
-    if (name is SimpleIdentifier) {
-      nameId = name;
-    } else if (name is _OperatorName) {
-      operatorKeyword = name.operatorKeyword;
-      nameId = name.name;
-    } else {
-      throw new UnimplementedError();
-    }
-
-    checkFieldFormalParameters(parameters);
-    currentDeclarationMembers.add(ast.methodDeclaration(
-        comment,
-        metadata,
-        modifiers?.externalKeyword,
-        modifiers?.abstractKeyword ?? modifiers?.staticKeyword,
-        returnType,
-        getOrSet,
-        operatorKeyword,
-        nameId,
-        typeParameters,
-        parameters,
-        body));
-  }
-
-  @override
-  void endMixinMethod(Token getOrSet, Token beginToken, Token beginParam,
-      Token beginInitializers, Token endToken) {
-    debugEvent("MixinMethod");
-    endClassMethod(
-        getOrSet, beginToken, beginParam, beginInitializers, endToken);
-  }
-
-  @override
-  void endExtensionMethod(Token getOrSet, Token beginToken, Token beginParam,
-      Token beginInitializers, Token endToken) {
-    debugEvent("ExtensionMethod");
-    endClassMethod(
-        getOrSet, beginToken, beginParam, beginInitializers, endToken);
-  }
-
-  @override
-  void endClassConstructor(Token getOrSet, Token beginToken, Token beginParam,
-      Token beginInitializers, Token endToken) {
-    assert(getOrSet == null ||
-        optional('get', getOrSet) ||
-        optional('set', getOrSet));
-    debugEvent("ClassConstructor");
-
-    var bodyObject = pop();
-    List<ConstructorInitializer> initializers = pop() ?? const [];
-    Token separator = pop();
-    FormalParameterList parameters = pop();
-    TypeParameterList typeParameters = pop();
-    var name = pop();
-    TypeAnnotation returnType = pop();
-    _Modifiers modifiers = pop();
-    List<Annotation> metadata = pop();
-    Comment comment = _findComment(metadata, beginToken);
-
-    assert(parameters != null || optional('get', getOrSet));
-
-    ConstructorName redirectedConstructor;
-    FunctionBody body;
-    if (bodyObject is FunctionBody) {
-      body = bodyObject;
-    } else if (bodyObject is _RedirectingFactoryBody) {
-      separator = bodyObject.equalToken;
-      redirectedConstructor = bodyObject.constructorName;
-      body = ast.emptyFunctionBody(endToken);
-    } else {
-      unhandled("${bodyObject.runtimeType}", "bodyObject",
-          beginToken.charOffset, uri);
-    }
-
-    SimpleIdentifier prefixOrName;
-    Token period;
-    SimpleIdentifier nameOrNull;
-    if (name is SimpleIdentifier) {
-      prefixOrName = name;
-    } else if (name is PrefixedIdentifier) {
-      prefixOrName = name.prefix;
-      period = name.period;
-      nameOrNull = name.identifier;
-    } else {
-      throw new UnimplementedError();
-    }
-
-    if (typeParameters != null) {
-      // Outline builder also reports this error message.
-      handleRecoverableError(messageConstructorWithTypeParameters,
-          typeParameters.beginToken, typeParameters.endToken);
-    }
-    if (modifiers?.constKeyword != null &&
-        body != null &&
-        (body.length > 1 || body.beginToken?.lexeme != ';')) {
-      // This error is also reported in BodyBuilder.finishFunction
-      Token bodyToken = body.beginToken ?? modifiers.constKeyword;
-      handleRecoverableError(
-          messageConstConstructorWithBody, bodyToken, bodyToken);
-    }
-    if (returnType != null) {
-      // This error is also reported in OutlineBuilder.endMethod
-      handleRecoverableError(messageConstructorWithReturnType,
-          returnType.beginToken, returnType.beginToken);
-    }
-    ConstructorDeclaration constructor = ast.constructorDeclaration(
-        comment,
-        metadata,
-        modifiers?.externalKeyword,
-        modifiers?.finalConstOrVarKeyword,
-        null,
-        // TODO(paulberry): factoryKeyword
-        ast.simpleIdentifier(prefixOrName.token),
-        period,
-        nameOrNull,
-        parameters,
-        separator,
-        initializers,
-        redirectedConstructor,
-        body);
-    currentDeclarationMembers.add(constructor);
-    if (mixinDeclaration != null) {
-      // TODO (danrubel): Report an error if this is a mixin declaration.
-    }
-  }
-
-  @override
   void endMixinConstructor(Token getOrSet, Token beginToken, Token beginParam,
       Token beginInitializers, Token endToken) {
     debugEvent("MixinConstructor");
@@ -1740,31 +1739,34 @@
   }
 
   @override
-  void endExtensionConstructor(Token getOrSet, Token beginToken,
-      Token beginParam, Token beginInitializers, Token endToken) {
-    debugEvent("ExtensionConstructor");
-    // TODO(danrubel) Decide how to handle constructor declarations within
-    // extensions. They are invalid and the parser has already reported an
-    // error at this point. In the future, we should include them in order
-    // to get navigation, search, etc.
-    pop(); // body
-    pop(); // initializers
-    pop(); // separator
-    pop(); // parameters
-    pop(); // typeParameters
-    pop(); // name
-    pop(); // returnType
-    pop(); // modifiers
-    pop(); // metadata
-  }
-
-  @override
   void endMixinDeclaration(Token mixinKeyword, Token endToken) {
     debugEvent("MixinDeclaration");
     mixinDeclaration = null;
   }
 
   @override
+  void endMixinFactoryMethod(
+      Token beginToken, Token factoryKeyword, Token endToken) {
+    debugEvent("MixinFactoryMethod");
+    endClassFactoryMethod(beginToken, factoryKeyword, endToken);
+  }
+
+  @override
+  void endMixinFields(Token staticToken, Token covariantToken, Token lateToken,
+      Token varFinalOrConst, int count, Token beginToken, Token endToken) {
+    endClassFields(staticToken, covariantToken, lateToken, varFinalOrConst,
+        count, beginToken, endToken);
+  }
+
+  @override
+  void endMixinMethod(Token getOrSet, Token beginToken, Token beginParam,
+      Token beginInitializers, Token endToken) {
+    debugEvent("MixinMethod");
+    endClassMethod(
+        getOrSet, beginToken, beginParam, beginInitializers, endToken);
+  }
+
+  @override
   void endNamedFunctionExpression(Token endToken) {
     debugEvent("NamedFunctionExpression");
     FunctionBody body = pop();
@@ -2752,7 +2754,8 @@
     if (node is ConstructorName) {
       push(new _ConstructorNameWithInvalidTypeArgs(node, invalidTypeArgs));
     } else {
-      throw new UnimplementedError();
+      throw new UnimplementedError(
+          'node is an instance of ${node.runtimeType} in handleInvalidTypeArguments');
     }
   }
 
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index b28a0af..9072fbd 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -5426,11 +5426,12 @@
               // Try to pattern match matchingInterfaceType against
               // mixinSupertypeConstraint to find the correct set of type
               // parameters to apply to the mixin.
-              var matchedType = _typeSystem.matchSupertypeConstraints(
-                  mixinElement,
-                  mixinSupertypeConstraints,
-                  matchingInterfaceTypes);
-              if (matchedType == null) {
+              var inferredTypeArguments = _typeSystem.matchSupertypeConstraints(
+                mixinElement,
+                mixinSupertypeConstraints,
+                matchingInterfaceTypes,
+              );
+              if (inferredTypeArguments == null) {
                 _errorReporter.reportErrorForToken(
                     CompileTimeErrorCode
                         .MIXIN_INFERENCE_NO_POSSIBLE_SUBSTITUTION,
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 1a6ab3f..5685ba6 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -585,12 +585,9 @@
     return false;
   }
 
-  /// Given some [Element], look at the associated metadata and report the use
-  /// of the member if it is declared as deprecated.
-  ///
-  /// @param element some element to check for deprecated use of
-  /// @param node the node use for the location of the error
-  /// See [HintCode.DEPRECATED_MEMBER_USE].
+  /// Given some [element], look at the associated metadata and report the use
+  /// of the member if it is declared as deprecated. If a diagnostic is reported
+  /// it should be reported at the given [node].
   void _checkForDeprecatedMemberUse(Element element, AstNode node) {
     bool isDeprecated(Element element) {
       if (element is PropertyAccessorElement && element.isSynthetic) {
@@ -650,10 +647,19 @@
       }
       LibraryElement library =
           element is LibraryElement ? element : element.library;
-      HintCode hintCode = _isLibraryInWorkspacePackage(library)
-          ? HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE
-          : HintCode.DEPRECATED_MEMBER_USE;
-      _errorReporter.reportErrorForNode(hintCode, node, [displayName]);
+      String message = _deprecatedMessage(element);
+      if (message == null || message.isEmpty) {
+        HintCode hintCode = _isLibraryInWorkspacePackage(library)
+            ? HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE
+            : HintCode.DEPRECATED_MEMBER_USE;
+        _errorReporter.reportErrorForNode(hintCode, node, [displayName]);
+      } else {
+        HintCode hintCode = _isLibraryInWorkspacePackage(library)
+            ? HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE_WITH_MESSAGE
+            : HintCode.DEPRECATED_MEMBER_USE_WITH_MESSAGE;
+        _errorReporter
+            .reportErrorForNode(hintCode, node, [displayName, message]);
+      }
     }
   }
 
@@ -1234,6 +1240,22 @@
     return _workspacePackage.contains(library.source);
   }
 
+  /// Return the message in the deprecated annotation on the given [element], or
+  /// `null` if the element doesn't have a deprecated annotation or if the
+  /// annotation does not have a message.
+  static String _deprecatedMessage(Element element) {
+    ElementAnnotationImpl annotation = element.metadata.firstWhere(
+      (e) => e.isDeprecated,
+      orElse: () => null,
+    );
+    if (annotation == null || annotation.element is PropertyAccessorElement) {
+      return null;
+    }
+    DartObject constantValue = annotation.computeConstantValue();
+    return constantValue?.getField('message')?.toStringValue() ??
+        constantValue?.getField('expires')?.toStringValue();
+  }
+
   /// Check for the passed class declaration for the
   /// [HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE] hint code.
   ///
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 5d44d4b..260c049 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -2161,29 +2161,17 @@
    */
   static FunctionType constructorToGenericFunctionType(
       ConstructorElement constructor) {
-    // TODO(jmesserly): it may be worth making this available from the
-    // constructor. It's nice if our inference code can operate uniformly on
-    // function types.
-    ClassElement cls = constructor.enclosingElement;
-    FunctionType type = constructor.type;
-    if (cls.typeParameters.isEmpty) {
-      return type;
+    var classElement = constructor.enclosingElement;
+    var typeParameters = classElement.typeParameters;
+    if (typeParameters.isEmpty) {
+      return constructor.type;
     }
 
-    // Create a synthetic function type using the class type parameters,
-    // and then rename it with fresh variables.
-    var name = cls.name;
-    if (constructor.name != null) {
-      name += '.' + constructor.name;
-    }
-    var function = new FunctionElementImpl(name, -1);
-    function.enclosingElement = cls.enclosingElement;
-    function.isSynthetic = true;
-    function.returnType = type.returnType;
-    function.shareTypeParameters(cls.typeParameters);
-    function.shareParameters(type.parameters);
-    function.type = new FunctionTypeImpl(function);
-    return new FunctionTypeImpl.fresh(function.type);
+    return FunctionTypeImpl.synthetic(
+      constructor.returnType,
+      typeParameters,
+      constructor.parameters,
+    );
   }
 
   static DartType _getFreshType(DartType type) {
diff --git a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
index 810d916..e3d001e 100644
--- a/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/ast_test_factory.dart
@@ -7,6 +7,8 @@
 import 'package:analyzer/dart/ast/standard_ast_factory.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/nullability_suffix.dart';
+import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/generated/testing/token_factory.dart';
 import 'package:analyzer/src/generated/utilities_dart.dart';
 import 'package:meta/meta.dart';
@@ -1323,7 +1325,13 @@
     SimpleIdentifier name = identifier3(element.name);
     name.staticElement = element;
     TypeName typeName = typeName3(name, arguments);
-    typeName.type = element.type;
+    typeName.type = element.instantiate(
+      typeArguments: List.filled(
+        element.typeParameters.length,
+        DynamicTypeImpl.instance,
+      ),
+      nullabilitySuffix: NullabilitySuffix.star,
+    );
     return typeName;
   }
 
diff --git a/pkg/analyzer/lib/src/generated/testing/element_factory.dart b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
index 0ed4131..94530e8 100644
--- a/pkg/analyzer/lib/src/generated/testing/element_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/element_factory.dart
@@ -7,6 +7,7 @@
 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/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart';
@@ -29,6 +30,7 @@
    * The element representing the class 'Object'.
    */
   static ClassElementImpl _objectElement;
+  static InterfaceType _objectType;
 
   static ClassElementImpl get object {
     if (_objectElement == null) {
@@ -37,7 +39,12 @@
     return _objectElement;
   }
 
-  static InterfaceType get objectType => object.type;
+  static InterfaceType get objectType {
+    return _objectType ??= object.instantiate(
+      typeArguments: const [],
+      nullabilitySuffix: NullabilitySuffix.star,
+    );
+  }
 
   static ClassElementImpl classElement(
       String typeName, InterfaceType superclassType,
@@ -150,7 +157,10 @@
     // Build the enum.
     //
     EnumElementImpl enumElement = new EnumElementImpl(enumName, -1);
-    InterfaceTypeImpl enumType = enumElement.type;
+    InterfaceTypeImpl enumType = enumElement.instantiate(
+      typeArguments: const [],
+      nullabilitySuffix: NullabilitySuffix.star,
+    );
     //
     // Populate the fields.
     //
@@ -276,10 +286,11 @@
     for (int i = 0; i < totalCount; i++) {
       ParameterElementImpl parameter = new ParameterElementImpl("a$i", i);
       if (i < normalCount) {
-        parameter.type = normalParameters[i].type;
+        parameter.type = _typeDefiningElementType(normalParameters[i]);
         parameter.parameterKind = ParameterKind.REQUIRED;
       } else {
-        parameter.type = optionalParameters[i - normalCount].type;
+        parameter.type =
+            _typeDefiningElementType(optionalParameters[i - normalCount]);
         parameter.parameterKind = ParameterKind.POSITIONAL;
       }
       parameters[i] = parameter;
@@ -312,13 +323,14 @@
     for (int i = 0; i < totalCount; i++) {
       if (i < normalCount) {
         ParameterElementImpl parameter = new ParameterElementImpl("a$i", i);
-        parameter.type = normalParameters[i].type;
+        parameter.type = _typeDefiningElementType(normalParameters[i]);
         parameter.parameterKind = ParameterKind.REQUIRED;
         parameters[i] = parameter;
       } else {
         ParameterElementImpl parameter =
             new ParameterElementImpl(names[i - normalCount], i);
-        parameter.type = namedParameters[i - normalCount].type;
+        parameter.type =
+            _typeDefiningElementType(namedParameters[i - normalCount]);
         parameter.parameterKind = ParameterKind.NAMED;
         parameters[i] = parameter;
       }
@@ -328,7 +340,7 @@
     if (returnElement == null) {
       functionElement.returnType = VoidTypeImpl.instance;
     } else {
-      functionElement.returnType = returnElement.type;
+      functionElement.returnType = _typeDefiningElementType(returnElement);
     }
     return functionElement;
   }
@@ -650,4 +662,17 @@
     typeParameter.bound = bound;
     return typeParameter;
   }
+
+  static DartType _typeDefiningElementType(TypeDefiningElement element) {
+    if (element is ClassElement) {
+      return element.instantiate(
+        typeArguments: List.filled(
+          element.typeParameters.length,
+          DynamicTypeImpl.instance,
+        ),
+        nullabilitySuffix: NullabilitySuffix.star,
+      );
+    }
+    throw ArgumentError('element: (${element.runtimeType}) $element');
+  }
 }
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index d64f2d5..888ec81 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -785,9 +785,12 @@
     }
     // For a type parameter `T extends U`, allow promoting the upper bound
     // `U` to `S` where `S <: U`, yielding a type parameter `T extends S`.
-    if (from is TypeParameterType) {
+    if (from is TypeParameterTypeImpl) {
       if (isSubtypeOf(to, from.bound ?? DynamicTypeImpl.instance)) {
-        return new TypeParameterMember(from.element, null, to).type;
+        var newElement = TypeParameterMember(from.element, null, to);
+        return newElement.instantiate(
+          nullabilitySuffix: from.nullabilitySuffix,
+        );
       }
     }
 
@@ -2493,33 +2496,35 @@
     return type.withNullability(NullabilitySuffix.question);
   }
 
-  /// Attempts to find the appropriate substitution for [typeParameters] that can
-  /// be applied to [src] to make it equal to [dest].  If no such substitution can
-  /// be found, `null` is returned.
-  InterfaceType matchSupertypeConstraints(
-      ClassElement mixinElement, List<DartType> srcs, List<DartType> dests) {
+  /// Attempts to find the appropriate substitution for the [mixinElement]
+  /// type parameters that can be applied to [srcTypes] to make it equal to
+  /// [destTypes].  If no such substitution can be found, `null` is returned.
+  List<DartType> matchSupertypeConstraints(
+    ClassElement mixinElement,
+    List<DartType> srcTypes,
+    List<DartType> destTypes,
+  ) {
     var typeParameters = mixinElement.typeParameters;
     var inferrer = new GenericInferrer(typeProvider, this, typeParameters);
-    for (int i = 0; i < srcs.length; i++) {
-      inferrer.constrainReturnType(srcs[i], dests[i]);
-      inferrer.constrainReturnType(dests[i], srcs[i]);
+    for (int i = 0; i < srcTypes.length; i++) {
+      inferrer.constrainReturnType(srcTypes[i], destTypes[i]);
+      inferrer.constrainReturnType(destTypes[i], srcTypes[i]);
     }
 
     var inferredTypes = inferrer.infer(
       typeParameters,
       considerExtendsClause: false,
     );
-    var result = mixinElement.type.instantiate(inferredTypes);
+    var substitution = Substitution.fromPairs(typeParameters, inferredTypes);
 
-    for (int i = 0; i < srcs.length; i++) {
-      if (srcs[i].substitute2(
-              result.typeArguments, mixinElement.type.typeArguments) !=
-          dests[i]) {
+    for (int i = 0; i < srcTypes.length; i++) {
+      if (substitution.substituteType(srcTypes[i]) != destTypes[i]) {
         // Failed to find an appropriate substitution
         return null;
       }
     }
-    return result;
+
+    return inferredTypes;
   }
 
   /**
diff --git a/pkg/analyzer/lib/src/summary2/linking_bundle_context.dart b/pkg/analyzer/lib/src/summary2/linking_bundle_context.dart
index 6f003ab..bdd01ea 100644
--- a/pkg/analyzer/lib/src/summary2/linking_bundle_context.dart
+++ b/pkg/analyzer/lib/src/summary2/linking_bundle_context.dart
@@ -51,6 +51,7 @@
 
   int indexOfElement(Element element) {
     if (element == null) return 0;
+    if (element is MultiplyDefinedElement) return 0;
     assert(element is! Member);
 
     if (identical(element, DynamicElementImpl.instance)) {
diff --git a/pkg/analyzer/lib/src/summary2/types_builder.dart b/pkg/analyzer/lib/src/summary2/types_builder.dart
index b60d334..f470c13 100644
--- a/pkg/analyzer/lib/src/summary2/types_builder.dart
+++ b/pkg/analyzer/lib/src/summary2/types_builder.dart
@@ -2,8 +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.
 
+import 'package:analyzer/dart/analysis/features.dart';
 import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/nullability_suffix.dart';
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/element.dart';
 import 'package:analyzer/src/dart/element/type.dart';
@@ -179,12 +181,21 @@
 /// Performs mixins inference in a [ClassDeclaration].
 class _MixinInference {
   final Dart2TypeSystem typeSystem;
+  final FeatureSet featureSet;
+  final InterfaceType classType;
 
-  InterfaceType classType;
   List<InterfaceType> mixinTypes = [];
   List<InterfaceType> supertypesForMixinInference;
 
-  _MixinInference(this.typeSystem, this.classType);
+  _MixinInference(this.typeSystem, this.featureSet, this.classType);
+
+  NullabilitySuffix get _noneOrStarSuffix {
+    return _nonNullableEnabled
+        ? NullabilitySuffix.none
+        : NullabilitySuffix.star;
+  }
+
+  bool get _nonNullableEnabled => featureSet.isEnabled(Feature.non_nullable);
 
   void perform(WithClause withClause) {
     if (withClause == null) return;
@@ -282,12 +293,16 @@
     // Try to pattern match matchingInterfaceTypes against
     // mixinSupertypeConstraints to find the correct set of type
     // parameters to apply to the mixin.
-    var inferredMixin = typeSystem.matchSupertypeConstraints(
+    var inferredTypeArguments = typeSystem.matchSupertypeConstraints(
       mixinElement,
       mixinSupertypeConstraints,
       matchingInterfaceTypes,
     );
-    if (inferredMixin != null) {
+    if (inferredTypeArguments != null) {
+      var inferredMixin = mixinElement.instantiate(
+        typeArguments: inferredTypeArguments,
+        nullabilitySuffix: _noneOrStarSuffix,
+      );
       mixinType = inferredMixin;
       mixinNode.type = inferredMixin;
     }
@@ -342,7 +357,9 @@
   void _infer(ClassElementImpl element, WithClause withClause) {
     element.linkedMixinInferenceCallback = _callbackWhenLoop;
     try {
-      _MixinInference(typeSystem, element.thisType).perform(withClause);
+      var featureSet = _unitFeatureSet(element);
+      _MixinInference(typeSystem, featureSet, element.thisType)
+          .perform(withClause);
     } finally {
       element.linkedMixinInferenceCallback = null;
     }
@@ -355,4 +372,9 @@
       _infer(node.declaredElement, node.withClause);
     }
   }
+
+  static FeatureSet _unitFeatureSet(ClassElementImpl element) {
+    var unit = element.linkedNode.parent as CompilationUnit;
+    return unit.featureSet;
+  }
 }
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index 0c0a8e6..58f6c69 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -1525,8 +1525,13 @@
     if (members.isEmpty) return covariantChecks;
 
     for (var iface in covariantInterfaces) {
-      var unsafeSupertype =
-          rules.instantiateToBounds(iface.type) as InterfaceType;
+      var typeParameters = iface.typeParameters;
+      var defaultTypeArguments =
+          rules.instantiateTypeFormalsToBounds(typeParameters);
+      var unsafeSupertype = iface.instantiate(
+        typeArguments: defaultTypeArguments,
+        nullabilitySuffix: NullabilitySuffix.star,
+      );
       for (var m in members) {
         _findCovariantChecksForMember(m, unsafeSupertype, covariantChecks);
       }
diff --git a/pkg/analyzer/lib/src/task/strong_mode.dart b/pkg/analyzer/lib/src/task/strong_mode.dart
index a4707b5..a57c953 100644
--- a/pkg/analyzer/lib/src/task/strong_mode.dart
+++ b/pkg/analyzer/lib/src/task/strong_mode.dart
@@ -154,19 +154,7 @@
           parameter, index, overriddenTypes[i].parameters);
       DartType type = matchingParameter?.type ?? typeProvider.dynamicType;
       if (parameterType == null) {
-        if (type is FunctionType &&
-            type.element != null &&
-            type.element is! TypeDefiningElement &&
-            type.element.enclosingElement is! TypeDefiningElement) {
-          // The resulting parameter's type element has an `enclosingElement` of
-          // the overridden parameter. Change it to the overriding parameter.
-          parameterType = new FunctionTypeImpl.fresh(type, force: true);
-          (parameterType.element as ElementImpl).enclosingElement = parameter;
-          // TODO(mfairhurst) handle cases where non-functions contain functions
-          // See test_inferredType_parameter_genericFunctionType_asTypeArgument
-        } else {
-          parameterType = type;
-        }
+        parameterType = type;
       } else if (parameterType != type) {
         if (parameter is ParameterElementImpl && parameter.linkedNode != null) {
           LazyAst.setTypeInferenceError(
diff --git a/pkg/analyzer/test/src/dart/element/element_test.dart b/pkg/analyzer/test/src/dart/element/element_test.dart
index 9d5b46d..d6e9dc2 100644
--- a/pkg/analyzer/test/src/dart/element/element_test.dart
+++ b/pkg/analyzer/test/src/dart/element/element_test.dart
@@ -1697,40 +1697,6 @@
     expect(s.isSubtypeOf(t), isFalse);
   }
 
-  void test_namedParameterTypes_pruned_no_type_arguments() {
-    var f = ElementFactory.genericTypeAliasElement('f');
-    var g = ElementFactory.genericTypeAliasElement('g');
-    f.function.parameters = [
-      ElementFactory.namedParameter2('x', functionTypeAliasType(g))
-    ];
-    FunctionTypeImpl paramType =
-        functionTypeAliasType(f).namedParameterTypes['x'];
-    expect(paramType.prunedTypedefs, hasLength(1));
-    expect(paramType.prunedTypedefs[0], same(f));
-  }
-
-  void test_namedParameterTypes_pruned_with_type_arguments() {
-    var f = ElementFactory.genericTypeAliasElement('f');
-    var g = ElementFactory.genericTypeAliasElement('g');
-    f.typeParameters = [ElementFactory.typeParameterElement('T')];
-    f.function.parameters = [
-      ElementFactory.namedParameter2('x', functionTypeAliasType(g))
-    ];
-    FunctionTypeImpl paramType =
-        functionTypeAliasType(f, typeArguments: [typeProvider.intType])
-            .namedParameterTypes['x'];
-    expect(paramType.prunedTypedefs, hasLength(1));
-    expect(paramType.prunedTypedefs[0], same(f));
-  }
-
-  void test_newPrune_no_previous_prune() {
-    var f = ElementFactory.genericTypeAliasElement('f');
-    FunctionTypeImpl type = functionTypeAliasType(f);
-    List<FunctionTypeAliasElement> pruneList = type.newPrune;
-    expect(pruneList, hasLength(1));
-    expect(pruneList[0], same(f));
-  }
-
   void test_newPrune_non_typedef() {
     // No pruning needs to be done for function types that aren't associated
     // with typedefs because those types can't be directly referred to by the
@@ -1740,80 +1706,6 @@
     expect(type.newPrune, isNull);
   }
 
-  void test_newPrune_synthetic_typedef() {
-    // No pruning needs to be done for function types that are associated with
-    // synthetic typedefs because those types are only created for
-    // function-typed formal parameters, which can't be directly referred to by
-    // the user (and hence can't participate in circularities).
-    var f = ElementFactory.genericTypeAliasElement('f');
-    f.isSynthetic = true;
-    FunctionTypeImpl type = functionTypeAliasType(f);
-    expect(type.newPrune, isNull);
-  }
-
-  void test_newPrune_with_previous_prune() {
-    var f = ElementFactory.genericTypeAliasElement('f');
-    var g = ElementFactory.genericTypeAliasElement('g');
-    FunctionTypeImpl type = functionTypeAliasType(f);
-    FunctionTypeImpl prunedType = type.pruned([g]);
-    List<FunctionTypeAliasElement> pruneList = prunedType.newPrune;
-    expect(pruneList, hasLength(2));
-    expect(pruneList, contains(f));
-    expect(pruneList, contains(g));
-  }
-
-  void test_normalParameterTypes_pruned_no_type_arguments() {
-    var f = ElementFactory.genericTypeAliasElement('f');
-    var g = ElementFactory.genericTypeAliasElement('g');
-    f.function.parameters = [
-      ElementFactory.requiredParameter2('x', functionTypeAliasType(g))
-    ];
-    FunctionTypeImpl paramType =
-        functionTypeAliasType(f).normalParameterTypes[0];
-    expect(paramType.prunedTypedefs, hasLength(1));
-    expect(paramType.prunedTypedefs[0], same(f));
-  }
-
-  void test_normalParameterTypes_pruned_with_type_arguments() {
-    var f = ElementFactory.genericTypeAliasElement('f');
-    var g = ElementFactory.genericTypeAliasElement('g');
-    f.typeParameters = [ElementFactory.typeParameterElement('T')];
-    f.function.parameters = [
-      ElementFactory.requiredParameter2('x', functionTypeAliasType(g))
-    ];
-    FunctionTypeImpl paramType =
-        functionTypeAliasType(f, typeArguments: [typeProvider.intType])
-            .normalParameterTypes[0];
-    expect(paramType.prunedTypedefs, hasLength(1));
-    expect(paramType.prunedTypedefs[0], same(f));
-  }
-
-  void test_optionalParameterTypes_pruned_no_type_arguments() {
-    var f = ElementFactory.genericTypeAliasElement('f');
-    var g = ElementFactory.genericTypeAliasElement('g');
-    f.function.parameters = [
-      ElementFactory.positionalParameter2('x', functionTypeAliasType(g))
-    ];
-    FunctionTypeImpl paramType =
-        functionTypeAliasType(f).optionalParameterTypes[0];
-    expect(paramType.prunedTypedefs, hasLength(1));
-    expect(paramType.prunedTypedefs[0], same(f));
-  }
-
-  void test_optionalParameterTypes_pruned_with_type_arguments() {
-    var f = ElementFactory.genericTypeAliasElement('f');
-    var g = ElementFactory.genericTypeAliasElement('g');
-    f.typeParameters = [ElementFactory.typeParameterElement('T')];
-    f.function.parameters = [
-      ElementFactory.positionalParameter2('x', functionTypeAliasType(g))
-    ];
-    FunctionTypeImpl paramType =
-        functionTypeAliasType(f, typeArguments: [typeProvider.intType])
-            .optionalParameterTypes[0];
-    expect(paramType.prunedTypedefs, hasLength(1));
-    expect(paramType.prunedTypedefs[0], same(f));
-  }
-
   void test_resolveToBound() {
     FunctionElementImpl f = ElementFactory.functionElement('f');
     FunctionTypeImpl type = f.type;
@@ -1822,27 +1714,6 @@
     expect(type.resolveToBound(null), same(type));
   }
 
-  void test_returnType_pruned_no_type_arguments() {
-    var f = ElementFactory.genericTypeAliasElement('f');
-    var g = ElementFactory.genericTypeAliasElement('g');
-    f.function.returnType = functionTypeAliasType(g);
-    FunctionTypeImpl paramType = functionTypeAliasType(f).returnType;
-    expect(paramType.prunedTypedefs, hasLength(1));
-    expect(paramType.prunedTypedefs[0], same(f));
-  }
-
-  void test_returnType_pruned_with_type_arguments() {
-    var f = ElementFactory.genericTypeAliasElement('f');
-    var g = ElementFactory.genericTypeAliasElement('g');
-    f.typeParameters = [ElementFactory.typeParameterElement('T')];
-    f.function.returnType = functionTypeAliasType(g);
-    FunctionTypeImpl paramType =
-        functionTypeAliasType(f, typeArguments: [typeProvider.intType])
-            .returnType;
-    expect(paramType.prunedTypedefs, hasLength(1));
-    expect(paramType.prunedTypedefs[0], same(f));
-  }
-
   void test_substitute2_equal() {
     ClassElementImpl definingClass = ElementFactory.classElement2("C", ["E"]);
     TypeParameterType parameterType =
@@ -1916,7 +1787,10 @@
     var s = ElementFactory.genericTypeAliasElement("s");
     t.function.returnType = functionTypeAliasType(s);
     s.function.returnType = functionTypeAliasType(t);
-    expect(functionTypeAliasType(t).toString(), '... Function() Function()');
+    expect(
+      functionTypeAliasType(t).toString(),
+      'dynamic Function() Function()',
+    );
   }
 
   void test_toString_recursive_via_interface_type() {
@@ -1926,7 +1800,10 @@
       typeArguments: [functionTypeAliasType(f)],
       nullabilitySuffix: NullabilitySuffix.star,
     );
-    expect(functionTypeAliasType(f).toString(), 'C<...> Function()');
+    expect(
+      functionTypeAliasType(f).toString(),
+      'C<dynamic Function()> Function()',
+    );
   }
 
   void test_typeParameters_genericLocalFunction_genericMethod_genericClass() {
diff --git a/pkg/analyzer/test/src/dart/element/function_type_test.dart b/pkg/analyzer/test/src/dart/element/function_type_test.dart
index 0b79a60..23e92cc 100644
--- a/pkg/analyzer/test/src/dart/element/function_type_test.dart
+++ b/pkg/analyzer/test/src/dart/element/function_type_test.dart
@@ -116,351 +116,6 @@
         nullabilitySuffix: NullabilitySuffix.star,
       );
 
-  test_forInstantiatedTypedef_bothTypeParameters_noTypeArgs() {
-    // typedef F<T> = Map<T, U> Function<U>();
-    var t = typeParameter('T');
-    var u = typeParameter('U');
-    var e = genericTypeAliasElement('F',
-        typeParameters: [t],
-        innerTypeParameters: [u],
-        returnType: mapOf(typeParameterType(t), typeParameterType(u)));
-    FunctionType f = new FunctionTypeImpl.forTypedef(e);
-    // Note: forTypedef returns the type `<T>() -> Map<T, U>`.
-    // See https://github.com/dart-lang/sdk/issues/34657.
-    basicChecks(f,
-        element: same(e),
-        displayName: 'F',
-        name: 'F',
-        typeFormals: [same(t)],
-        returnType: mapOf(typeParameterType(t), typeParameterType(u)));
-  }
-
-  test_forInstantiatedTypedef_innerTypeParameter_noTypeArgs() {
-    // typedef F = T F<T>();
-    var t = typeParameter('T');
-    var e = genericTypeAliasElement('F',
-        innerTypeParameters: [t], returnType: typeParameterType(t));
-    FunctionType f = new FunctionTypeImpl.forTypedef(e);
-    // Note: forTypedef returns the type `() -> T`.
-    // See https://github.com/dart-lang/sdk/issues/34657.
-    basicChecks(f,
-        element: same(e),
-        displayName: 'F',
-        name: 'F',
-        returnType: typeParameterType(t));
-  }
-
-  test_forInstantiatedTypedef_noTypeParameters_noTypeArgs() {
-    // typedef F = void Function();
-    var e = genericTypeAliasElement('F');
-    FunctionType f = new FunctionTypeImpl.forTypedef(e);
-    // Note: forTypedef returns the type `() -> void`.
-    basicChecks(f, element: same(e), displayName: 'F', name: 'F');
-  }
-
-  test_forInstantiatedTypedef_outerTypeParameters_noTypeArgs() {
-    // typedef F<T> = T Function();
-    var t = typeParameter('T');
-    var e = genericTypeAliasElement('F',
-        typeParameters: [t], returnType: typeParameterType(t));
-    FunctionType f = new FunctionTypeImpl.forTypedef(e);
-    // Note: forTypedef returns the type `<T>() -> T`.
-    // See https://github.com/dart-lang/sdk/issues/34657.
-    basicChecks(f,
-        element: same(e),
-        displayName: 'F',
-        name: 'F',
-        typeFormals: [same(t)],
-        returnType: typeParameterType(t));
-  }
-
-  test_forTypedef() {
-    var e = genericTypeAliasElement('F');
-    basicChecks(functionTypeAliasType(e),
-        element: same(e), displayName: 'F', name: 'F');
-    basicChecks(e.function.type,
-        element: same(e.function), displayName: 'dynamic Function()');
-  }
-
-  test_forTypedef_innerAndOuterTypeParameter() {
-    // typedef F<T> = T Function<U>(U p);
-    var t = typeParameter('T');
-    var u = typeParameter('U');
-    var p = requiredParameter('p', type: typeParameterType(u));
-    var e = genericTypeAliasElement('F',
-        typeParameters: [t],
-        innerTypeParameters: [u],
-        returnType: typeParameterType(t),
-        parameters: [p]);
-    basicChecks(e.type,
-        element: same(e),
-        displayName: 'F',
-        name: 'F',
-        returnType: typeParameterType(t),
-        normalParameterTypes: [typeParameterType(u)],
-        normalParameterNames: ['p'],
-        parameters: [same(p)],
-        typeFormals: [same(t)]);
-    basicChecks(e.function.type,
-        element: same(e.function),
-        displayName: 'T Function<U>(U)',
-        returnType: typeParameterType(t),
-        typeArguments: [typeParameterType(t)],
-        typeParameters: [same(t)],
-        typeFormals: [same(u)],
-        normalParameterTypes: [typeParameterType(u)],
-        normalParameterNames: ['p'],
-        parameters: [same(p)]);
-  }
-
-  test_forTypedef_innerAndOuterTypeParameter_instantiate() {
-    // typedef F<T> = T Function<U>(U p);
-    var t = typeParameter('T');
-    var u = typeParameter('U');
-    var p = requiredParameter('p', type: typeParameterType(u));
-    var e = genericTypeAliasElement('F',
-        typeParameters: [t],
-        innerTypeParameters: [u],
-        returnType: typeParameterType(t),
-        parameters: [p]);
-    var instantiated = functionTypeAliasType(e, typeArguments: [objectType]);
-    basicChecks(instantiated,
-        element: same(e),
-        displayName: 'F<Object>',
-        name: 'F',
-        returnType: same(objectType),
-        normalParameterTypes: [typeParameterType(u)],
-        normalParameterNames: ['p'],
-        parameters: [same(p)],
-        typeFormals: isNotNull,
-        typeArguments: [same(objectType)],
-        typeParameters: [same(t)]);
-    if (bug_33294_fixed) {
-      expect(instantiated.typeFormals, [same(u)]);
-    } else {
-      expect(instantiated.typeFormals, isEmpty);
-    }
-  }
-
-  test_forTypedef_innerTypeParameter() {
-    // typedef F = T Function<T>();
-    var t = typeParameter('T');
-    var e = genericTypeAliasElement('F',
-        innerTypeParameters: [t], returnType: typeParameterType(t));
-    basicChecks(functionTypeAliasType(e),
-        element: same(e),
-        displayName: 'F',
-        name: 'F',
-        returnType: typeParameterType(t));
-    basicChecks(e.function.type,
-        element: same(e.function),
-        displayName: 'T Function<T>()',
-        returnType: typeParameterType(t),
-        typeFormals: [same(t)]);
-  }
-
-  test_forTypedef_normalParameter() {
-    var p = requiredParameter('p', type: dynamicType);
-    var e = genericTypeAliasElement('F', parameters: [p]);
-    basicChecks(functionTypeAliasType(e),
-        element: same(e),
-        displayName: 'F',
-        name: 'F',
-        normalParameterNames: ['p'],
-        normalParameterTypes: [same(dynamicType)],
-        parameters: [same(p)]);
-    basicChecks(e.function.type,
-        element: same(e.function),
-        displayName: 'dynamic Function(dynamic)',
-        normalParameterNames: ['p'],
-        normalParameterTypes: [same(dynamicType)],
-        parameters: [same(p)]);
-  }
-
-  test_forTypedef_recursive_via_interfaceTypes() {
-    // typedef F = List<G> Function();
-    // typedef G = List<F> Function();
-    var f = genericTypeAliasElement('F');
-    var g = genericTypeAliasElement('G');
-    f.function.returnType = listOf(g.function.type);
-    g.function.returnType = listOf(f.function.type);
-    basicChecks(functionTypeAliasType(f),
-        element: same(f), displayName: 'F', name: 'F', returnType: isNotNull);
-    var fReturn = functionTypeAliasType(f).returnType;
-    expect(fReturn.element, same(listElement));
-    if (bug_33302_fixed) {
-      expect(fReturn.displayName, 'List<G>');
-    } else {
-      expect(fReturn.displayName, 'List<List<...> Function()>');
-    }
-    var fReturnArg = (fReturn as InterfaceType).typeArguments[0];
-    expect(fReturnArg.element, same(g.function));
-    var fReturnArgReturn = (fReturnArg as FunctionType).returnType;
-    expect(fReturnArgReturn.element, same(listElement));
-    expect((fReturnArgReturn as InterfaceType).typeArguments[0],
-        new TypeMatcher<CircularFunctionTypeImpl>());
-    basicChecks(f.function.type,
-        element: same(f.function), displayName: isNotNull, returnType: fReturn);
-    if (bug_33302_fixed) {
-      expect(f.function.type.displayName, 'List<G> Function()');
-    } else {
-      expect(
-          f.function.type.displayName, 'List<List<...> Function()> Function()');
-    }
-    basicChecks(functionTypeAliasType(g),
-        element: same(g), displayName: 'G', name: 'G', returnType: isNotNull);
-    var gReturn = functionTypeAliasType(g).returnType;
-    expect(gReturn.element, same(listElement));
-    if (bug_33302_fixed) {
-      expect(gReturn.displayName, 'List<F>');
-    } else {
-      expect(gReturn.displayName, 'List<List<...> Function()>');
-    }
-    var gReturnArg = (gReturn as InterfaceType).typeArguments[0];
-    expect(gReturnArg.element, same(f.function));
-    var gReturnArgReturn = (gReturnArg as FunctionType).returnType;
-    expect(gReturnArgReturn.element, same(listElement));
-    expect((gReturnArgReturn as InterfaceType).typeArguments[0],
-        new TypeMatcher<CircularFunctionTypeImpl>());
-    basicChecks(g.function.type,
-        element: same(g.function), displayName: isNotNull, returnType: gReturn);
-    if (bug_33302_fixed) {
-      expect(g.function.type.displayName, 'F Function()');
-    } else {
-      expect(
-          g.function.type.displayName, 'List<List<...> Function()> Function()');
-    }
-  }
-
-  test_forTypedef_recursive_via_parameterTypes() {
-    // typedef F = void Function(G g);
-    // typedef G = void Function(F f);
-    var f = genericTypeAliasElement('F', returnType: voidType);
-    var g = genericTypeAliasElement('G', returnType: voidType);
-    f.function.parameters = [requiredParameter('g', type: g.function.type)];
-    g.function.parameters = [requiredParameter('f', type: f.function.type)];
-    basicChecks(functionTypeAliasType(f),
-        element: same(f),
-        displayName: 'F',
-        name: 'F',
-        parameters: hasLength(1),
-        normalParameterTypes: hasLength(1),
-        normalParameterNames: ['g'],
-        returnType: same(voidType));
-    var fParamType = functionTypeAliasType(f).normalParameterTypes[0];
-    expect(fParamType.element, same(g.function));
-    expect((fParamType as FunctionType).normalParameterTypes[0],
-        new TypeMatcher<CircularFunctionTypeImpl>());
-    basicChecks(f.function.type,
-        element: same(f.function),
-        displayName: isNotNull,
-        parameters: hasLength(1),
-        normalParameterTypes: [fParamType],
-        normalParameterNames: ['g'],
-        returnType: same(voidType));
-    if (bug_33302_fixed) {
-      expect(f.function.type.displayName, 'void Function(G)');
-    } else {
-      expect(f.function.type.displayName, 'void Function(void Function(...))');
-    }
-    basicChecks(functionTypeAliasType(g),
-        element: same(g),
-        displayName: 'G',
-        name: 'G',
-        parameters: hasLength(1),
-        normalParameterTypes: hasLength(1),
-        normalParameterNames: ['f'],
-        returnType: same(voidType));
-    var gParamType = functionTypeAliasType(g).normalParameterTypes[0];
-    expect(gParamType.element, same(f.function));
-    expect((gParamType as FunctionType).normalParameterTypes[0],
-        new TypeMatcher<CircularFunctionTypeImpl>());
-    basicChecks(g.function.type,
-        element: same(g.function),
-        displayName: isNotNull,
-        parameters: hasLength(1),
-        normalParameterTypes: [gParamType],
-        normalParameterNames: ['f'],
-        returnType: same(voidType));
-    if (bug_33302_fixed) {
-      expect(g.function.type.displayName, 'void Function(F)');
-    } else {
-      expect(g.function.type.displayName, 'void Function(void Function(...))');
-    }
-  }
-
-  test_forTypedef_recursive_via_returnTypes() {
-    // typedef F = G Function();
-    // typedef G = F Function();
-    var f = genericTypeAliasElement('F');
-    var g = genericTypeAliasElement('G');
-    f.function.returnType = g.function.type;
-    g.function.returnType = f.function.type;
-    basicChecks(functionTypeAliasType(f),
-        element: same(f), displayName: 'F', name: 'F', returnType: isNotNull);
-    var fReturn = functionTypeAliasType(f).returnType;
-    expect(fReturn.element, same(g.function));
-    expect((fReturn as FunctionType).returnType,
-        new TypeMatcher<CircularFunctionTypeImpl>());
-    basicChecks(f.function.type,
-        element: same(f.function), displayName: isNotNull, returnType: fReturn);
-    if (bug_33302_fixed) {
-      expect(f.function.type.displayName, 'G Function()');
-    } else {
-      expect(f.function.type.displayName, '... Function() Function()');
-    }
-    basicChecks(functionTypeAliasType(g),
-        element: same(g), displayName: 'G', name: 'G', returnType: isNotNull);
-    var gReturn = functionTypeAliasType(g).returnType;
-    expect(gReturn.element, same(f.function));
-    expect((gReturn as FunctionType).returnType,
-        new TypeMatcher<CircularFunctionTypeImpl>());
-    basicChecks(g.function.type,
-        element: same(g.function), displayName: isNotNull, returnType: gReturn);
-    if (bug_33302_fixed) {
-      expect(g.function.type.displayName, 'F Function()');
-    } else {
-      expect(g.function.type.displayName, '... Function() Function()');
-    }
-  }
-
-  test_forTypedef_returnType() {
-    var e = genericTypeAliasElement('F', returnType: objectType);
-    basicChecks(functionTypeAliasType(e),
-        element: same(e), displayName: 'F', name: 'F', returnType: objectType);
-    basicChecks(e.function.type,
-        element: same(e.function),
-        displayName: 'Object Function()',
-        returnType: objectType);
-  }
-
-  test_forTypedef_returnType_null() {
-    var e = genericTypeAliasElement('F');
-    basicChecks(functionTypeAliasType(e),
-        element: same(e), displayName: 'F', name: 'F');
-    basicChecks(e.function.type,
-        element: same(e.function), displayName: 'dynamic Function()');
-  }
-
-  test_forTypedef_typeParameter() {
-    // typedef F<T> = T Function();
-    var t = typeParameter('T');
-    var e = genericTypeAliasElement('F',
-        typeParameters: [t], returnType: typeParameterType(t));
-    basicChecks(e.type,
-        element: same(e),
-        displayName: 'F',
-        name: 'F',
-        returnType: typeParameterType(t),
-        typeFormals: [same(t)]);
-    basicChecks(e.function.type,
-        element: same(e.function),
-        displayName: 'T Function()',
-        returnType: typeParameterType(t),
-        typeArguments: [typeParameterType(t)],
-        typeParameters: [same(t)]);
-  }
-
   test_synthetic() {
     FunctionType f = new FunctionTypeImpl.synthetic(dynamicType, [], []);
     basicChecks(f, element: isNull);
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 e88a6bc..a27a115 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
@@ -3,6 +3,7 @@
 // BSD-style license that can be found in the LICENSE file.
 
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/error/syntactic_errors.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
@@ -113,6 +114,20 @@
     assertNoTestErrors();
   }
 
+  test_missingGenericFunction() async {
+    await assertErrorsInCode(r'''
+typedef F<T> = ;
+
+void f() {
+  F.a;
+}
+''', [
+      error(ParserErrorCode.INVALID_GENERIC_FUNCTION_TYPE, 13, 1),
+      error(ParserErrorCode.EXPECTED_TYPE_NAME, 15, 1),
+      error(StaticTypeWarningCode.UNDEFINED_GETTER, 33, 1),
+    ]);
+  }
+
   test_type_element() async {
     await resolveTestCode(r'''
 G<int> g;
diff --git a/pkg/analyzer/test/src/diagnostics/deprecated_member_use_test.dart b/pkg/analyzer/test/src/diagnostics/deprecated_member_use_test.dart
index 4aa435c..e6cf43b 100644
--- a/pkg/analyzer/test/src/diagnostics/deprecated_member_use_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/deprecated_member_use_test.dart
@@ -306,7 +306,7 @@
   m() {}
   n() {m();}
 }
-''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE]);
+''', [HintCode.DEPRECATED_MEMBER_USE_FROM_SAME_PACKAGE_WITH_MESSAGE]);
   }
 
   test_operator() async {
@@ -614,7 +614,8 @@
     await assertErrorsInCode(r'''
 import 'package:foo/foo.dart';
 void main() => A().m();
-''', [HintCode.DEPRECATED_MEMBER_USE], sourceName: '/pkg1/lib/lib1.dart');
+''', [HintCode.DEPRECATED_MEMBER_USE_WITH_MESSAGE],
+        sourceName: '/pkg1/lib/lib1.dart');
   }
 
   test_packageBuildWorkspace() async {
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 54294ea..369d0fe 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -10867,12 +10867,48 @@
 
   test_unresolved_annotation_simpleIdentifier() async {
     var library = await checkLibrary('@foo class C {}', allowErrors: true);
-    checkElementText(library, r'''
-@
-        foo/*location: null*/
+    checkElementText(
+        library,
+        r'''
 class C {
 }
+  metadata
+    Annotation
+      element: <null>
+      name: SimpleIdentifier
+        staticElement: <null>
+        staticType: dynamic
+        token: foo
+''',
+        withFullyResolvedAst: true);
+  }
+
+  test_unresolved_annotation_simpleIdentifier_multiplyDefined() async {
+    addLibrarySource('/a.dart', 'const v = 0;');
+    addLibrarySource('/b.dart', 'const v = 0;');
+    var library = await checkLibrary('''
+import 'a.dart';
+import 'b.dart';
+
+@v
+class C {}
 ''');
+    checkElementText(
+        library,
+        r'''
+import 'a.dart';
+import 'b.dart';
+class C {
+}
+  metadata
+    Annotation
+      element: <null>
+      name: SimpleIdentifier
+        staticElement: <null>
+        staticType: dynamic
+        token: v
+''',
+        withFullyResolvedAst: true);
   }
 
   test_unresolved_annotation_unnamedConstructorCall_noClass() async {
diff --git a/pkg/analyzer/test/src/task/options_test.dart b/pkg/analyzer/test/src/task/options_test.dart
index 0c311e0..653e1ee 100644
--- a/pkg/analyzer/test/src/task/options_test.dart
+++ b/pkg/analyzer/test/src/task/options_test.dart
@@ -11,7 +11,6 @@
 import 'package:analyzer/src/analysis_options/analysis_options_provider.dart';
 import 'package:analyzer/src/analysis_options/error/option_codes.dart';
 import 'package:analyzer/src/dart/error/hint_codes.dart';
-import 'package:analyzer/src/dart/error/syntactic_errors.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/file_system/file_system.dart';
 import 'package:analyzer/src/generated/engine.dart';
@@ -149,14 +148,21 @@
 @reflectiveTest
 class ErrorCodeValuesTest {
   test_errorCodes() {
+    // Now that we're using unique names for comparison, the only reason to
+    // split the codes by class is to find all of the classes that need to be
+    // checked against `errorCodeValues`.
     var errorTypeMap = <Type, List<ErrorCode>>{};
     for (ErrorCode code in errorCodeValues) {
-      errorTypeMap.putIfAbsent(code.runtimeType, () => <ErrorCode>[]).add(code);
+      Type type = code.runtimeType;
+      if (type == HintCodeWithUniqueName) {
+        type = HintCode;
+      }
+      errorTypeMap.putIfAbsent(type, () => <ErrorCode>[]).add(code);
     }
 
-    int missingErrorCodeCount = 0;
+    StringBuffer missingCodes = StringBuffer();
     errorTypeMap.forEach((Type errorType, List<ErrorCode> codes) {
-      var listedNames = codes.map((ErrorCode code) => code.name).toSet();
+      var listedNames = codes.map((ErrorCode code) => code.uniqueName).toSet();
 
       var declaredNames = reflectClass(errorType)
           .declarations
@@ -165,115 +171,23 @@
         String name = declarationMirror.simpleName.toString();
         //TODO(danrubel): find a better way to extract the text from the symbol
         assert(name.startsWith('Symbol("') && name.endsWith('")'));
-        return name.substring(8, name.length - 2);
+        return errorType.toString() + '.' + name.substring(8, name.length - 2);
       }).where((String name) {
         return name == name.toUpperCase();
       }).toList();
 
-      // Remove declared names that are not supposed to be in errorCodeValues
-
-      if (errorType == AnalysisOptionsErrorCode) {
-        declaredNames
-            .remove(AnalysisOptionsErrorCode.INCLUDED_FILE_PARSE_ERROR.name);
-      } else if (errorType == AnalysisOptionsWarningCode) {
-        declaredNames
-            .remove(AnalysisOptionsWarningCode.INCLUDE_FILE_NOT_FOUND.name);
-        declaredNames
-            .remove(AnalysisOptionsWarningCode.INCLUDED_FILE_WARNING.name);
-        declaredNames
-            .remove(AnalysisOptionsWarningCode.INVALID_SECTION_FORMAT.name);
-      } else if (errorType == StaticWarningCode) {
-        declaredNames.remove(
-            StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS.name +
-                '_PLUS');
-        declaredNames.remove('EXTRA_POSITIONAL_ARGUMENTS');
-        declaredNames.remove('EXTRA_POSITIONAL_ARGUMENTS_COULD_BE_NAMED');
-        declaredNames.remove('IMPORT_OF_NON_LIBRARY');
-        declaredNames.remove('NOT_ENOUGH_REQUIRED_ARGUMENTS');
-        declaredNames.remove('REDIRECT_TO_MISSING_CONSTRUCTOR');
-        declaredNames.remove('REDIRECT_TO_NON_CLASS');
-        declaredNames.remove('UNDEFINED_CLASS');
-        declaredNames.remove('UNDEFINED_NAMED_PARAMETER');
-      } else if (errorType == StrongModeCode) {
-        void removeCode(StrongModeCode code) {
-          declaredNames.remove(code.name);
-        }
-
-        removeCode(StrongModeCode.DOWN_CAST_COMPOSITE);
-        removeCode(StrongModeCode.DOWN_CAST_IMPLICIT);
-        removeCode(StrongModeCode.DOWN_CAST_IMPLICIT_ASSIGN);
-        removeCode(StrongModeCode.DYNAMIC_CAST);
-        removeCode(StrongModeCode.ASSIGNMENT_CAST);
-        removeCode(StrongModeCode.INVALID_PARAMETER_DECLARATION);
-        removeCode(StrongModeCode.COULD_NOT_INFER);
-        removeCode(StrongModeCode.INFERRED_TYPE);
-        removeCode(StrongModeCode.INFERRED_TYPE_LITERAL);
-        removeCode(StrongModeCode.INFERRED_TYPE_ALLOCATION);
-        removeCode(StrongModeCode.INFERRED_TYPE_CLOSURE);
-        removeCode(StrongModeCode.INVALID_CAST_LITERAL);
-        removeCode(StrongModeCode.INVALID_CAST_LITERAL_LIST);
-        removeCode(StrongModeCode.INVALID_CAST_LITERAL_MAP);
-        removeCode(StrongModeCode.INVALID_CAST_LITERAL_SET);
-        removeCode(StrongModeCode.INVALID_CAST_FUNCTION_EXPR);
-        removeCode(StrongModeCode.INVALID_CAST_NEW_EXPR);
-        removeCode(StrongModeCode.INVALID_CAST_METHOD);
-        removeCode(StrongModeCode.INVALID_CAST_FUNCTION);
-        removeCode(StrongModeCode.INVALID_SUPER_INVOCATION);
-        removeCode(StrongModeCode.NON_GROUND_TYPE_CHECK_INFO);
-        removeCode(StrongModeCode.DYNAMIC_INVOKE);
-        removeCode(StrongModeCode.IMPLICIT_DYNAMIC_PARAMETER);
-        removeCode(StrongModeCode.IMPLICIT_DYNAMIC_RETURN);
-        removeCode(StrongModeCode.IMPLICIT_DYNAMIC_VARIABLE);
-        removeCode(StrongModeCode.IMPLICIT_DYNAMIC_FIELD);
-        removeCode(StrongModeCode.IMPLICIT_DYNAMIC_TYPE);
-        removeCode(StrongModeCode.IMPLICIT_DYNAMIC_LIST_LITERAL);
-        removeCode(StrongModeCode.IMPLICIT_DYNAMIC_MAP_LITERAL);
-        removeCode(StrongModeCode.IMPLICIT_DYNAMIC_FUNCTION);
-        removeCode(StrongModeCode.IMPLICIT_DYNAMIC_METHOD);
-        removeCode(StrongModeCode.IMPLICIT_DYNAMIC_INVOKE);
-        removeCode(StrongModeCode.NOT_INSTANTIATED_BOUND);
-        removeCode(StrongModeCode.TOP_LEVEL_CYCLE);
-        removeCode(StrongModeCode.TOP_LEVEL_FUNCTION_LITERAL_BLOCK);
-        removeCode(StrongModeCode.TOP_LEVEL_IDENTIFIER_NO_TYPE);
-        removeCode(StrongModeCode.TOP_LEVEL_INSTANCE_GETTER);
-        removeCode(StrongModeCode.TOP_LEVEL_INSTANCE_METHOD);
-      } else if (errorType == TodoCode) {
-        declaredNames.remove('TODO_REGEX');
-      } else if (errorType == CompileTimeErrorCode) {
-        declaredNames.remove('ANNOTATION_WITH_TYPE_ARGUMENTS');
-        declaredNames.remove('NOT_ENOUGH_REQUIRED_ARGUMENTS');
-      } else if (errorType == ParserErrorCode) {
-        declaredNames.remove('CONST_AFTER_FACTORY');
-        declaredNames.remove('CONST_AND_COVARIANT');
-        declaredNames.remove('CONST_AND_VAR');
-        declaredNames.remove('COVARIANT_AFTER_FINAL');
-        declaredNames.remove('COVARIANT_AFTER_VAR');
-        declaredNames.remove('EXTERNAL_AFTER_CONST');
-        declaredNames.remove('EXTERNAL_AFTER_FACTORY');
-        declaredNames.remove('EXTERNAL_AFTER_STATIC');
-        declaredNames.remove('MISSING_CLASS_BODY');
-        declaredNames.remove('STATIC_AFTER_CONST');
-        declaredNames.remove('STATIC_AFTER_FINAL');
-        declaredNames.remove('STATIC_AFTER_VAR');
-      }
-
-      // Assert that all remaining declared names are in errorCodeValues
+      // Assert that all declared names are in errorCodeValues
 
       for (String declaredName in declaredNames) {
         if (!listedNames.contains(declaredName)) {
-          ++missingErrorCodeCount;
-          print('   errorCodeValues is missing $errorType $declaredName');
+          missingCodes.writeln();
+          missingCodes.write('  $declaredName');
         }
       }
     });
-    expect(missingErrorCodeCount, 0, reason: 'missing error code names');
-
-    // Apparently, duplicate error codes are allowed
-    //    expect(
-    //      ErrorFilterOptionValidator.errorCodes.length,
-    //      errorCodeValues.length,
-    //      reason: 'some errorCodeValues have the same name',
-    //    );
+    if (missingCodes.isNotEmpty) {
+      fail('Missing error codes:$missingCodes');
+    }
   }
 }
 
diff --git a/pkg/analyzer/tool/diagnostics/diagnostics.md b/pkg/analyzer/tool/diagnostics/diagnostics.md
index daa7d2a..8757439 100644
--- a/pkg/analyzer/tool/diagnostics/diagnostics.md
+++ b/pkg/analyzer/tool/diagnostics/diagnostics.md
@@ -1937,7 +1937,7 @@
 #### Common fixes
 
 If you don't need to support older versions of the SDK, then you can
-ncrease the SDK constraint to allow the expression to be used:
+increase the SDK constraint to allow the expression to be used:
 
 ```yaml
 environment:
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart
index 7e9a695..adb9abc 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common_elements.dart
@@ -499,6 +499,7 @@
   FieldEntity get rtiCheckField;
   FieldEntity get rtiIsField;
   FieldEntity get rtiRestField;
+  FieldEntity get rtiPrecomputed1Field;
   FunctionEntity get rtiEvalMethod;
   FunctionEntity get rtiBindMethod;
   FunctionEntity get rtiAddRulesMethod;
@@ -1914,6 +1915,11 @@
   @override
   FieldEntity get rtiRestField => _rtiRestField ??= _findRtiClassField('_rest');
 
+  FieldEntity _rtiPrecomputed1Field;
+  @override
+  FieldEntity get rtiPrecomputed1Field =>
+      _rtiPrecomputed1Field ??= _findRtiClassField('_precomputed1');
+
   FunctionEntity _rtiEvalMethod;
   @override
   FunctionEntity get rtiEvalMethod =>
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index ffcfc5c..dd132e5 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -1060,6 +1060,17 @@
 }
 
 void main(List<String> arguments) {
+  // Expand `@path/to/file`
+  // When running from bazel, argument of the form `@path/to/file` might be
+  // provided. It needs to be replaced by reading all the contents of the
+  // file and expanding them into the resulting argument list.
+  //
+  // TODO: Move this logic to a single place and share it among all tools.
+  if (arguments.last.startsWith('@')) {
+    var extra = _readLines(arguments.last.substring(1));
+    arguments = arguments.take(arguments.length - 1).followedBy(extra).toList();
+  }
+
   // Since the sdk/bin/dart2js script adds its own arguments in front of
   // user-supplied arguments we search for '--batch' at the end of the list.
   if (arguments.length > 0 && arguments.last == "--batch") {
@@ -1069,6 +1080,11 @@
   internalMain(arguments);
 }
 
+/// Return all non-empty lines in a file found at [path].
+Iterable<String> _readLines(String path) {
+  return File(path).readAsLinesSync().where((line) => line.isNotEmpty);
+}
+
 typedef void ExitFunc(int exitCode);
 typedef Future<api.CompilationResult> CompileFunc(
     CompilerOptions compilerOptions,
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 02c690d..bdecdbc 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types_new.dart
@@ -141,8 +141,6 @@
   final List<jsAst.Literal> _fragments = [];
   final List<int> _codes = [];
 
-  RuntimeTypesNeed get _rtiNeed => _encoder._rtiNeed;
-
   _RecipeGenerator(
       this._encoder, this._emitter, this._environment, this._recipe,
       {this.metadata = false, this.hackTypeVariablesToAny = false});
@@ -260,26 +258,14 @@
       }
     }
     if (environment is FullTypeEnvironmentStructure) {
-      int i = environment.bindings.indexOf(type);
-      if (i >= 0) {
-        // Indexes are 1-based since '0' encodes using the entire type for the
-        // singleton structure.
-        _emitInteger(i + 1);
-        return;
-      }
-
-      int index = _indexIntoClassTypeVariables(type);
+      int index = indexTypeVariable(
+          _closedWorld, _rtiSubstitutions, environment, type,
+          metadata: metadata);
       if (index != null) {
-        // We should only observe erased type arguments if we're generating
-        // subtype metadata.
-        assert(metadata ||
-            _rtiNeed.classNeedsTypeArguments(environment.classType.element));
-
-        // Indexed class type variables come after the bound function type
-        // variables.
-        _emitInteger(1 + environment.bindings.length + index);
+        _emitInteger(index);
         return;
       }
+
       jsAst.Name name = _emitter.typeVariableAccessNewRti(type.element);
       _emitName(name);
       typeVariables.add(type);
@@ -290,35 +276,6 @@
     '`$type`'.codeUnits.forEach(_emitCode);
   }
 
-  int /*?*/ _indexIntoClassTypeVariables(TypeVariableType variable) {
-    TypeVariableEntity element = variable.element;
-    ClassEntity cls = element.typeDeclaration;
-
-    if (metadata) {
-      TypeEnvironmentStructure environment = _environment;
-      if (environment is FullTypeEnvironmentStructure) {
-        if (identical(environment.classType.element, cls)) {
-          return element.index;
-        }
-      }
-    }
-
-    // TODO(sra): We might be in a context where the class type variable has an
-    // index, even though in the general case it is not at a specific index.
-
-    ClassHierarchy classHierarchy = _closedWorld.classHierarchy;
-    var test = mustCheckAllSubtypes(_closedWorld, cls)
-        ? classHierarchy.anyStrictSubtypeOf
-        : classHierarchy.anyStrictSubclassOf;
-
-    if (test(cls, (ClassEntity subclass) {
-      return !_rtiSubstitutions.isTrivialSubstitution(subclass, cls);
-    })) {
-      return null;
-    }
-    return element.index;
-  }
-
   @override
   void visitFunctionTypeVariable(FunctionTypeVariable type, _) {
     int position = functionTypeVariables.indexOf(type);
@@ -479,6 +436,49 @@
     world.isUsedAsMixin(cls) ||
     world.extractTypeArgumentsInterfacesNewRti.contains(cls);
 
+int indexTypeVariable(
+    JClosedWorld world,
+    RuntimeTypesSubstitutions rtiSubstitutions,
+    FullTypeEnvironmentStructure environment,
+    TypeVariableType type,
+    {bool metadata = false}) {
+  int i = environment.bindings.indexOf(type);
+  if (i >= 0) {
+    // Indices are 1-based since '0' encodes using the entire type for the
+    // singleton structure.
+    return i + 1;
+  }
+
+  TypeVariableEntity element = type.element;
+  ClassEntity cls = element.typeDeclaration;
+
+  if (metadata) {
+    if (identical(environment.classType.element, cls)) {
+      // Indexed class type variables come after the bound function type
+      // variables.
+      return 1 + environment.bindings.length + element.index;
+    }
+  }
+
+  // TODO(sra): We might be in a context where the class type variable has an
+  // index, even though in the general case it is not at a specific index.
+
+  ClassHierarchy classHierarchy = world.classHierarchy;
+  var test = mustCheckAllSubtypes(world, cls)
+      ? classHierarchy.anyStrictSubtypeOf
+      : classHierarchy.anyStrictSubclassOf;
+  if (test(cls, (ClassEntity subclass) {
+    return !rtiSubstitutions.isTrivialSubstitution(subclass, cls);
+  })) {
+    return null;
+  }
+
+  assert(world.rtiNeed.classNeedsTypeArguments(environment.classType.element));
+  // Indexed class type variables come after the bound function type
+  // variables.
+  return 1 + environment.bindings.length + element.index;
+}
+
 class _RulesetEntry {
   Set<InterfaceType> _supertypes = {};
   Map<TypeVariableType, DartType> _typeVariables = {};
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 158413d..71ed092 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -28,9 +28,10 @@
 import '../js_backend/runtime_types.dart';
 import '../js_backend/runtime_types_codegen.dart';
 import '../js_backend/runtime_types_new.dart'
-    show RecipeEncoder, RecipeEncoding;
+    show RecipeEncoder, RecipeEncoding, indexTypeVariable;
 import '../js_emitter/code_emitter_task.dart' show ModularEmitter;
 import '../js_model/elements.dart' show JGeneratorBody;
+import '../js_model/type_recipe.dart';
 import '../native/behavior.dart';
 import '../options.dart';
 import '../tracer.dart';
@@ -2211,6 +2212,14 @@
     }
   }
 
+  js.Expression _loadField(js.Expression receiver, FieldEntity field,
+      SourceInformation sourceInformation) {
+    _registry.registerStaticUse(StaticUse.fieldGet(field));
+    js.Name name = _namer.instanceFieldPropertyName(field);
+    return js.PropertyAccess(receiver, name)
+        .withSourceInformation(sourceInformation);
+  }
+
   @override
   visitFieldGet(HFieldGet node) {
     use(node.receiver);
@@ -2221,11 +2230,7 @@
       push(new js.PropertyAccess.field(pop(), 'toString')
           .withSourceInformation(node.sourceInformation));
     } else {
-      FieldEntity field = node.element;
-      js.Name name = _namer.instanceFieldPropertyName(field);
-      push(new js.PropertyAccess(pop(), name)
-          .withSourceInformation(node.sourceInformation));
-      _registry.registerStaticUse(new StaticUse.fieldGet(field));
+      push(_loadField(pop(), node.element, node.sourceInformation));
     }
   }
 
@@ -3472,6 +3477,44 @@
     // Call `env._eval("recipe")`.
     use(node.inputs[0]);
     js.Expression environment = pop();
+
+    // Instead of generating `env._eval("$n")`, generate appropriate field
+    // accesses where possible.
+    TypeEnvironmentStructure envStructure = node.envStructure;
+    TypeRecipe typeExpression = node.typeExpression;
+    if (envStructure is FullTypeEnvironmentStructure &&
+        typeExpression is TypeExpressionRecipe) {
+      if (typeExpression.type.isTypeVariable) {
+        TypeVariableType type = typeExpression.type;
+        int index = indexTypeVariable(
+            _closedWorld, _rtiSubstitutions, envStructure, type);
+        if (index != null) {
+          assert(index >= 1);
+          List<TypeVariableType> bindings = envStructure.bindings;
+          if (bindings.isNotEmpty) {
+            // If the environment is a binding RTI, we should never index past
+            // its length (i.e. into its base), since in that case, we could
+            // eval against the base directly.
+            assert(index <= bindings.length);
+          } else {
+            // If the environment is an interface RTI, use precomputed fields
+            // for common accesses.
+            if (index == 1) {
+              push(_loadField(environment, _commonElements.rtiPrecomputed1Field,
+                  node.sourceInformation));
+              return;
+            }
+          }
+
+          js.Expression rest = _loadField(environment,
+              _commonElements.rtiRestField, node.sourceInformation);
+          push(js.PropertyAccess.indexed(rest, index - 1)
+              .withSourceInformation(node.sourceInformation));
+          return;
+        }
+      }
+    }
+
     RecipeEncoding encoding = _rtiRecipeEncoder.encodeRecipe(
         _emitter, node.envStructure, node.typeExpression);
     js.Expression recipe = encoding.recipe;
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index d7d7140..d28f385 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -2098,10 +2098,20 @@
         _registry.registerInstantiation(constantValue.type);
         return HLoadType.type(constantValue.type, instance.instructionType);
       }
+      if (constantValue is ListConstantValue) {
+        InterfaceType type = constantValue.type;
+        _registry.registerInstantiation(type);
+        return HLoadType.type(type, instance.instructionType);
+      }
       return node;
     }
 
-    // TODO(sra): Store-forward list literal types.
+    if (instance is HInvokeStatic &&
+        instance.element == commonElements.setRuntimeTypeInfo) {
+      // TODO(sra): What is the 'instantiated type' we should be registering as
+      // discussed above? Perhaps it should be carried on HLiteralList.
+      return instance.inputs.last;
+    }
 
     return node;
   }
diff --git a/pkg/dart2native/bin/dart2native.dart b/pkg/dart2native/bin/dart2native.dart
index 475c993..700018b 100644
--- a/pkg/dart2native/bin/dart2native.dart
+++ b/pkg/dart2native/bin/dart2native.dart
@@ -91,26 +91,39 @@
 }
 
 Future<void> main(List<String> args) async {
-  final ArgParser parser = ArgParser()
+  // If we're outputting to a terminal, wrap usage text to that width.
+  int outputLineWidth = null;
+  try {
+    outputLineWidth = stdout.terminalColumns;
+  } catch (_) {/* Ignore. */}
+
+  final ArgParser parser = ArgParser(usageLineLength: outputLineWidth)
     ..addMultiOption('define', abbr: 'D', valueHelp: 'key=value', help: '''
-Set values of environment variables.
-To specify multiple variables, use multiple flags or use commas to separate pairs.
-Example:
-dart2native -Da=1,b=2 -Dc=3 --define=d=4 main.dart''')
+Set values of environment variables. To specify multiple variables, use multiple options or use commas to separate key-value pairs.
+E.g.: dart2native -Da=1,b=2 main.dart''')
     ..addFlag('enable-asserts',
         negatable: false, help: 'Enable assert statements.')
     ..addFlag('help',
-        abbr: 'h', negatable: false, help: 'Displays this help message.')
-    ..addOption('output',
-        abbr: 'o', valueHelp: 'path', help: 'Put the output in file <path>.')
-    ..addOption('output-kind',
-        abbr: 'k',
-        allowed: ['exe', 'aot'],
-        defaultsTo: 'exe',
-        valueHelp: 'exe|aot',
-        help: 'Generate a standalone executable or an AOT snapshot.')
-    ..addOption('packages',
-        abbr: 'p', valueHelp: 'path', help: 'Use the .packages file at <path>.')
+        abbr: 'h', negatable: false, help: 'Display this help message.')
+    ..addOption('output', abbr: 'o', valueHelp: 'path', help: '''
+Set the output filename. <path> can be relative or absolute.
+E.g.: dart2native main.dart -o ../bin/my_app.exe
+''')
+    ..addOption(
+      'output-kind',
+      abbr: 'k',
+      allowed: ['aot', 'exe'],
+      allowedHelp: {
+        'aot': 'Generate an AOT snapshot.',
+        'exe': 'Generate a standalone executable.',
+      },
+      defaultsTo: 'exe',
+      valueHelp: 'aot|exe',
+    )
+    ..addOption('packages', abbr: 'p', valueHelp: 'path', help: '''
+Get package locations from the specified file instead of .packages. <path> can be relative or absolute.
+E.g.: dart2native --packages=/tmp/pkgs main.dart
+''')
     ..addFlag('verbose',
         abbr: 'v', negatable: false, help: 'Show verbose output.');
 
diff --git a/pkg/dart2native/lib/dart2native.dart b/pkg/dart2native/lib/dart2native.dart
index 754fec9..7806861 100644
--- a/pkg/dart2native/lib/dart2native.dart
+++ b/pkg/dart2native/lib/dart2native.dart
@@ -5,8 +5,6 @@
 import 'dart:io';
 import 'dart:typed_data';
 
-import 'package:path/path.dart' as path;
-
 const appSnapshotPageSize = 4096;
 const appjitMagicNumber = <int>[0xdc, 0xdc, 0xf6, 0xf6, 0, 0, 0, 0];
 
@@ -64,8 +62,8 @@
 Future generateAotSnapshot(String genSnapshot, String kernelFile,
     String snapshotFile, bool enableAsserts) {
   return Process.run(genSnapshot, [
-    '--snapshot-kind=app-aot-blobs',
-    '--blobs_container_filename=${snapshotFile}',
+    '--snapshot-kind=app-aot-elf',
+    '--elf=${snapshotFile}',
     if (enableAsserts) '--enable-asserts',
     kernelFile
   ]);
diff --git a/pkg/dart2native/pubspec.yaml b/pkg/dart2native/pubspec.yaml
index be267fc..99e6f94 100644
--- a/pkg/dart2native/pubspec.yaml
+++ b/pkg/dart2native/pubspec.yaml
@@ -10,7 +10,6 @@
 
 dependencies:
    args: ^1.4.0
-   path:
 
 dev_dependencies:
 
diff --git a/pkg/dev_compiler/CHANGELOG.md b/pkg/dev_compiler/CHANGELOG.md
deleted file mode 100644
index e7da8f1..0000000
--- a/pkg/dev_compiler/CHANGELOG.md
+++ /dev/null
@@ -1,72 +0,0 @@
-# dev_compiler changelog
-
-## next release
-- add support for AMD modules and make it the default.
-- precompile the SDK in AMD, CommonJS, and ES6 flavors.
-- legacy module format is deprecated.
-- remove --package-paths option
-
-## 0.1.24
-- workaround breaking change on requestAnimationFrame
-
-## 0.1.23
-- updates for the latest analyzer
-- removal of deprecated functionality (server mode) in prep for refactoring
-
-## 0.1.22
-- fixes to support the latest analyzer
-- improvements in compile speed
-- bug fixes on function / closure handling
-
-## 0.1.21
-- bug fix for dart:js constructor invocation
-
-## 0.1.20
-- support new StackTrace.current method
-
-## 0.1.19
-- support for dom libraries (dart:html, etc)
-
-## 0.1.18
-- dart:typed_data support
-- preliminary TS / Closure output support
-- various runtime typing fixes
-
-## 0.1.17
-- preliminary node module support
-- support for compiling / serving multiple html files
-
-## 0.1.16
-- rolled analyzer to 0.27.2-alpha.1
-- fixes for static fields
-
-## 0.1.15
-- codegen fixes for dart:convert (json decode) and dart:math (max, min)
-
-## 0.1.14
-- updates to unpin analyzer and move forward to ^0.27.1+2
-
-## 0.1.13
-- various fixes in js codegen
-- pinned to analyzer 0.26.2+1 to avoid breaking upstream changes
-
-## 0.1.12
-- fixes for babel
-- fixes toward new js interop
-
-## 0.1.11
-- moved js runtime files to lib/runtime/dart (`dart_runtime.js` -> `dart/_runtime.js`)
-- bug fix to source maps
-- initial support for f-bound quantification patterns
-
-## 0.1.10
-- added an `--html-report` option to create a file summarizing compilation
-  issues
-- added a `-f` alias to the `--force-compile` command line option
-- removed many info level messages that were informational to the DDC team
-
-## 0.1.9
-
-## 0.1.8
-- added a `--version` command-line option
-- added a new entry-point - `dev_compiler` - that aliases to `dartdevc`
diff --git a/pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart b/pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart
deleted file mode 100644
index 87caa77..0000000
--- a/pkg/dev_compiler/lib/src/kernel/analyzer_to_kernel.dart
+++ /dev/null
@@ -1,917 +0,0 @@
-// Copyright (c) 2018, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:collection';
-import 'dart:core' hide MapEntry;
-
-import 'package:analyzer/dart/element/element.dart' as a;
-import 'package:analyzer/dart/element/type.dart' as a;
-import 'package:analyzer/file_system/physical_file_system.dart' as a;
-import 'package:analyzer/src/context/context.dart' as a;
-import 'package:analyzer/src/dart/analysis/restricted_analysis_context.dart'
-    as a;
-import 'package:analyzer/src/dart/element/element.dart' as a;
-import 'package:analyzer/src/dart/element/member.dart' as a;
-import 'package:analyzer/src/dart/element/type.dart' as a;
-import 'package:analyzer/src/generated/constant.dart' as a;
-import 'package:analyzer/src/generated/engine.dart' as a;
-import 'package:analyzer/src/generated/resolver.dart' as a
-    show NamespaceBuilder, TypeProvider;
-import 'package:analyzer/src/generated/source.dart' as a;
-import 'package:analyzer/src/generated/type_system.dart' as a;
-import 'package:analyzer/src/summary/idl.dart' as a;
-import 'package:analyzer/src/summary/package_bundle_reader.dart' as a;
-import 'package:analyzer/src/summary/summary_sdk.dart' as a;
-import 'package:analyzer/src/summary2/linked_bundle_context.dart' as a;
-import 'package:analyzer/src/summary2/linked_element_factory.dart' as a;
-import 'package:analyzer/src/summary2/reference.dart' as a;
-import 'package:front_end/src/api_unstable/ddc.dart'
-    show RedirectingFactoryBody;
-import 'package:kernel/kernel.dart';
-import 'package:kernel/type_algebra.dart';
-
-import '../analyzer/type_utilities.dart' hide freeTypeParameters;
-import 'type_table.dart';
-
-/// Converts an Analyzer summary file to a Kernel [Component].
-///
-/// The first step is to use Analyzer's [a.StoreBasedSummaryResynthesizer] to
-/// deserialize the summary file into an [a.Element] model (that way we don't
-/// depend directly on the file format). Once we have elements, we visit them
-/// and construct the corresponding Kernel [Node]s.
-///
-/// The main entry points are [convertSdk] and [convertSummaries], which
-/// convert the SDK and input summaries, respectively.
-///
-/// Because we only need to convert summaries, we do not need to handle method
-/// bodies. This lets us avoid the complexity of converting Analyzer AST nodes
-/// (e.g. expressions, statements).
-///
-/// For constants we use Analyzer's constant evaluator compute the value from
-/// the data in the summary, and then create the appropriate Kernel node to
-/// reconstruct the constant (e.g. ListLiteral, ConstructorInvocation, etc).
-/// See [_visitConstant] for more information.
-///
-/// When something refers to an element, we normally create the [Reference] but
-/// leave its corresponding [NamedNode] empty until that element is visited and
-/// creates the Kernel node. This takes care of cycles, and avoids recursing too
-/// deeply as we convert elements.
-///
-/// Sometimes we need to convert an element eagerly (e.g. if we need to call
-/// members on an [InterfaceType] or [Supertype], we need to create its [Class]
-/// node). In that case we handle cycles in the visit method (e.g.
-/// [visitClassElement]) by creating the node and linking it to its reference
-/// before visiting anything else that might recurse.
-///
-/// Special care must be taken to make sure we link up all [Reference]s with
-/// their corresponding [NamedNode]. If we don't do this [verifyReferences]
-/// will throw an error. The fix is to figure out why we didn't visit the
-/// element for that reference (often this is due to Analyzer's synthetic
-/// fields/accessor elements; care must be taken to always reference the real
-/// element).
-///
-/// Because we're using Analyzer's summary resynthesizer, conversion is all or
-/// nothing: all summaries must be in Analyzer format, including the SDK.
-/// Now that we have this implementation, it may be possible to port code from
-/// Analyzer and modify it to resynthesize directly into Kernel trees, if we
-/// ever need to support a mix of Kernel and Analyzer summary files.
-class AnalyzerToKernel {
-  final a.LinkedElementFactory _resynth;
-  final a.SummaryDataStore _summaryData;
-  final a.TypeProvider types;
-  final a.Dart2TypeSystem rules;
-
-  final _references = HashMap<a.Element, Reference>();
-  final _typeParams = HashMap<a.TypeParameterElement, TypeParameter>();
-  final _namespaceBuilder = a.NamespaceBuilder();
-
-  AnalyzerToKernel._(this._resynth, this._summaryData)
-      : types = _resynth.analysisContext.typeProvider,
-        rules = _resynth.analysisContext.typeSystem as a.Dart2TypeSystem;
-
-  /// Create an Analyzer summary to Kernel tree converter, using the provided
-  /// [analyzerSdkSummary] and [summaryPaths].
-  ///
-  /// Once the converter is created, [convertSdk] should be called to convert
-  /// & return the SDK, followed by [convertSummaries] to convert & return the
-  /// converted summaries.
-  factory AnalyzerToKernel(
-      String analyzerSdkSummary, List<String> summaryPaths) {
-    var summaryData = a.SummaryDataStore(summaryPaths,
-        resourceProvider: a.PhysicalResourceProvider.INSTANCE,
-        disallowOverlappingSummaries: false);
-    var resynthesizer =
-        _createSummaryResynthesizer(summaryData, analyzerSdkSummary);
-    return AnalyzerToKernel._(resynthesizer, summaryData);
-  }
-
-  /// Converts the SDK summary to a Kernel component and returns it.
-  Component convertSdk() {
-    // _createContextForSummaries puts the SDK summary last in the summary data.
-    var sdkBundle = _summaryData.bundles.last;
-    assert(sdkBundle.linkedLibraryUris.every((u) => u.startsWith('dart:')));
-    var result = _toComponent(sdkBundle);
-    verifyReferences();
-    return result;
-  }
-
-  /// Converts the input summaries to Kernel components and return them.
-  ///
-  /// [convertSdk] must be called before this.
-  List<Component> convertSummaries() {
-    // Take all summaries except the SDK one, which is placed last in the list
-    // by _createContextForSummaries.
-    var bundles = _summaryData.bundles.take(_summaryData.bundles.length - 1);
-    var result = bundles.map(_toComponent).toList();
-    verifyReferences(); // assumption: convertSdk() is called first
-    return result;
-  }
-
-  void verifyReferences() {
-    _references.forEach((element, reference) {
-      // Ensure each reference has a corresponding node.
-      //
-      // If it's missing a node, CFE will fail and it is difficult to debug at
-      // that point because the name and element cannot be accessed.
-      //
-      // Typically this error means:
-      // - we didn't visit an element.
-      // - we didn't set the `reference: _reference(e)` for the Kernel node.
-      // - we referenced a synthetic element by mistake, such as referencing the
-      //   synthetic getter/setter, when we should've used the field.
-      if (reference.node == null) {
-        throw StateError('missing node for reference, element was: $element' +
-            (element.isSynthetic ? ' (synthetic)' : ''));
-      }
-    });
-  }
-
-  Component _toComponent(a.PackageBundle bundle) {
-    var libraries = <Library>[];
-    var uriToSource = <Uri, Source>{};
-
-    void addCompilationUnit(a.CompilationUnitElement unit) {
-      uriToSource[unit.source.uri] = Source(
-          unit.lineInfo.lineStarts,
-          [],
-          unit.uri != null ? Uri.base.resolve(unit.uri) : unit.source.uri,
-          unit.source.uri);
-    }
-
-    for (var uri in bundle.unlinkedUnitUris) {
-      if (_summaryData.isPartUnit(uri)) {
-        // Library parts are handled by their corresponding library.
-        continue;
-      }
-
-      var element = _resynth.libraryOfUri(uri);
-      libraries.add(visitLibraryElement(element));
-      addCompilationUnit(element.definingCompilationUnit);
-      element.parts.forEach(addCompilationUnit);
-    }
-    return Component(libraries: libraries, uriToSource: uriToSource);
-  }
-
-  Class visitClassElement(a.ClassElement e, [Library library]) {
-    var ref = _reference(e);
-    if (ref.node != null) return ref.asClass;
-
-    // Construct the Class first and link the reference. This ensures the
-    // (not yet finished) Class node will be returned on the line above, if we
-    // happen to re-enter this visit method.
-    var class_ = Class(
-        name: e.name,
-        isAbstract: e.isAbstract,
-        fileUri: e.source.uri,
-        reference: ref);
-
-    // Classes can be visited before their library (e.g. because they're a
-    // supertype of another class), so make sure to visit the library now.
-    library ??= visitLibraryElement(e.library);
-    library.addClass(class_);
-
-    class_.isMixinDeclaration = e.isMixin;
-    class_.typeParameters
-        .addAll(e.typeParameters.map(visitTypeParameterElement));
-
-    setParents(class_.typeParameters, class_);
-    class_.implementedTypes.addAll(e.interfaces.map(_typeToSupertype));
-
-    var fields = class_.fields;
-    var constructors = class_.constructors;
-    var procedures = class_.procedures;
-
-    fields.addAll(e.fields.where((f) => !f.isSynthetic).map(visitFieldElement));
-
-    var redirectingFactories = <Procedure>[];
-    for (var ctor in e.constructors) {
-      if (ctor.isFactory) {
-        var factory_ = _visitFactory(ctor);
-        procedures.add(factory_);
-        if (ctor.redirectedConstructor != null) {
-          redirectingFactories.add(factory_);
-        }
-      } else {
-        constructors.add(visitConstructorElement(ctor));
-      }
-    }
-    if (redirectingFactories.isNotEmpty) {
-      fields.add(_createRedirectingFactoryField(redirectingFactories, e));
-    }
-    procedures.addAll(e.methods.map(visitMethodElement));
-    procedures.addAll(e.accessors
-        .where((a) => !a.isSynthetic)
-        .map(visitPropertyAccessorElement));
-
-    setParents(fields, class_);
-    setParents(constructors, class_);
-    setParents(procedures, class_);
-
-    if (e.isMixinApplication) {
-      class_.mixedInType = _typeToSupertype(e.mixins.last);
-    }
-
-    var supertype = _typeToSupertype(e.supertype);
-    class_.supertype = _unrollMixinClasses(e, supertype, library);
-    _visitAnnotations(e.metadata, class_.addAnnotation);
-
-    // TODO(jmesserly): do we need covariance check stubs? We may be okay as
-    // since we're only handling dependencies here.
-    //
-    // But this may lead to redundant stubs (if CFE doesn't see one on a
-    // superclass) and/or break some assumptions in CFE.
-    return class_;
-  }
-
-  Supertype _unrollMixinClasses(
-      a.ClassElement e, Supertype supertype, Library library) {
-    // TODO(jmesserly): is this enough for mixin desugaring? It only does
-    // enough to create the intermediate classes.
-
-    // Documentation below assumes the given mixin application is in one of
-    // these forms:
-    //
-    //     class C extends S with M1, M2, M3;
-    //     class Named = S with M1, M2, M3;
-    //
-    // When we refer to the subclass, we mean `C` or `Named`.
-
-    /// The number of mixin classes to unroll.
-    ///
-    /// Named mixin applications have one less class. This can be illustrated
-    /// here:
-    ///
-    ///     class C extends S with M1, M2, M3 {}
-    ///     class Named = S with M1, M2, M3;
-    ///
-    /// For `C` we unroll 3 classes: _C&S&M1, _C&S&M1&M2, _C&S&M1&M2&M3.
-    /// For `Named` we unroll 2 classes: _Named&S&M1, _Named&S&M1&M2.
-    ///
-    /// The classes themselves will be generated as:
-    ///
-    ///     class C extends _C&S&M1&M2&M3 {}
-    ///     class Named = _Named&S&M1&M2 with M3;
-    ///
-    var unrollLength = e.mixins.length;
-    if (e.isMixinApplication) unrollLength--;
-    if (unrollLength <= 0) return supertype;
-
-    /// The mixin application's synthetic name.
-    ///
-    /// The full name of the mixin application is obtained by prepending the
-    /// name of the subclass (`C` or `Named` in the above examples) to the
-    /// running name. For the example `C`, that leads to these names:
-    ///
-    /// 1. `_C&S&M1`
-    /// 2. `_C&S&M1&M2`
-    /// 3. `_C&S&M1&M2&M3`.
-    var runningName = '_${e.name}&${e.supertype.name}';
-
-    /// The type variables used in the current supertype and mixin, or null
-    /// if this class doesn't have any type parameters.
-    var usedTypeVars = e.typeParameters.isNotEmpty
-        ? freeTypeParameters(supertype.asInterfaceType)
-        : null;
-
-    for (int i = 0; i < unrollLength; i++) {
-      var mixin = e.mixins[i];
-      runningName += "&${mixin.name}";
-
-      var mixedInType = _typeToSupertype(mixin);
-      List<TypeParameter> typeParameters;
-      if (usedTypeVars != null) {
-        // Any type params used by superclasses will continue to be used, plus
-        // anything additional that this mixin uses.
-        usedTypeVars.addAll(freeTypeParameters(mixedInType.asInterfaceType));
-        if (usedTypeVars.isNotEmpty) {
-          // Make fresh type parameters for this class, and then substitute them
-          // into supertype and mixin type arguments (if any).
-          var fresh = getFreshTypeParameters(usedTypeVars.toList());
-          typeParameters = fresh.freshTypeParameters;
-          supertype = fresh.substituteSuper(supertype);
-          mixedInType = fresh.substituteSuper(mixedInType);
-        }
-      }
-
-      var c = Class(
-          name: runningName,
-          isAbstract: true,
-          mixedInType: mixedInType,
-          supertype: supertype,
-          typeParameters: typeParameters,
-          fileUri: e.source.uri);
-
-      library.addClass(c);
-
-      // Compute the superclass to use for the next iteration of this loop.
-      //
-      // Any type arguments are in terms of the original class type parameters.
-      // This allows us to perform consistent substitutions and have the correct
-      // type arguments for the final supertype (that we return).
-      supertype = Supertype(
-          c,
-          typeParameters != null
-              ? List.of(usedTypeVars.map((t) => TypeParameterType(t)))
-              : []);
-    }
-
-    return supertype;
-  }
-
-  Constructor visitConstructorElement(a.ConstructorElement e) {
-    assert(!e.isFactory);
-    var ref = _reference(e);
-    if (ref.node != null) return ref.asConstructor;
-    // By convention, instance constructors return `void` in Kernel.
-    var function = _createFunction(e)..returnType = const VoidType();
-    var result = Constructor(function,
-        name: _getName(e),
-        isConst: e.isConst,
-        isExternal: e.isExternal,
-        isSynthetic: e.isSynthetic,
-        fileUri: e.source.uri,
-        reference: ref);
-    if (!result.isSynthetic) {
-      // TODO(jmesserly): CFE does not respect the synthetic bit on constructors
-      // so we set a bogus offset. This causes CFE to treat it as not synthetic.
-      //
-      // (The bug is in DillMemberBuilder.isSynthetic. Synthetic constructors
-      // have different semantics/optimizations in some cases, so it is
-      // important that the constructor is correctly marked.)
-      result.fileOffset = 1;
-    }
-    _visitAnnotations(e.metadata, result.addAnnotation);
-    return result;
-  }
-
-  Procedure _visitFactory(a.ConstructorElement e) {
-    var ref = _reference(e);
-    if (ref.node != null) return ref.asProcedure;
-
-    var result = Procedure.byReference(_getName(e), ProcedureKind.Factory, null,
-        isExternal: e.isExternal,
-        isConst: e.isConst,
-        isStatic: true,
-        fileUri: e.source.uri,
-        reference: ref);
-
-    _visitAnnotations(e.metadata, result.addAnnotation);
-
-    // Since the factory is static, we need to create fresh type parameters that
-    // match the ones in the enclosing class.
-    FreshTypeParameters fresh;
-    DartType Function(a.DartType) visitType;
-
-    if (e.enclosingElement.typeParameters.isNotEmpty) {
-      fresh = getFreshTypeParameters(
-          visitClassElement(e.enclosingElement).typeParameters);
-      visitType = (t) => fresh.substitute(_visitDartType(t, ensureNode: true));
-    } else {
-      visitType = _visitDartType;
-    }
-
-    result.function = _createFunction(e, fresh?.freshTypeParameters, visitType);
-    result.function.parent = result;
-
-    var redirect = e.redirectedConstructor;
-    if (redirect == null) return result;
-
-    // Get the raw constructor element before the type is applied.
-    var rawRedirect =
-        redirect is a.ConstructorMember ? redirect.baseElement : redirect;
-
-    // TODO(jmesserly): conceptually we only need a reference here, but
-    // RedirectingFactoryBody requires the complete node.
-    var ctor = rawRedirect.isFactory
-        ? _visitFactory(rawRedirect)
-        : visitConstructorElement(rawRedirect);
-
-    var redirectedType = redirect.type.returnType as a.InterfaceType;
-    var typeArgs = redirectedType.typeArguments.map(visitType).toList();
-    result.function.body = RedirectingFactoryBody(ctor, typeArgs);
-    return result;
-  }
-
-  Field _createRedirectingFactoryField(
-      List<Procedure> factories, a.ClassElement c) {
-    return Field(_getName(c, "_redirecting#"),
-        isStatic: true,
-        initializer: ListLiteral(List.of(factories.map((f) => StaticGet(f)))),
-        fileUri: c.source.uri);
-  }
-
-  LibraryDependency visitExportElement(a.ExportElement e) =>
-      LibraryDependency.byReference(
-          LibraryDependency.ExportFlag,
-          const [],
-          _reference(e.exportedLibrary),
-          null,
-          e.combinators.map(_visitCombinator).toList());
-
-  Field visitFieldElement(a.FieldElement e) {
-    var result = Field(_getName(e),
-        type: _visitDartType(e.type),
-        initializer: null,
-        isFinal: e.isFinal,
-        isConst: e.isConst,
-        isStatic: e.isStatic,
-        fileUri: e.source.uri,
-        reference: _reference(e));
-    if (!e.isFinal && !e.isConst) {
-      var class_ = e.enclosingElement as a.ClassElement;
-      if (class_.typeParameters.isNotEmpty) {
-        result.isGenericCovariantImpl = _isGenericCovariant(class_, e.type);
-      }
-    }
-    _visitAnnotations(e.metadata, result.addAnnotation);
-    return result;
-  }
-
-  Procedure visitFunctionElement(a.FunctionElement e) {
-    var result = Procedure.byReference(
-        _getName(e), ProcedureKind.Method, _createFunction(e),
-        isExternal: e.isExternal,
-        fileUri: e.source.uri,
-        isStatic: true,
-        reference: _reference(e));
-    _visitAnnotations(e.metadata, result.addAnnotation);
-    return result;
-  }
-
-  Typedef visitFunctionTypeAliasElement(a.FunctionTypeAliasElement e,
-      [Library library]) {
-    var ref = _reference(e);
-    if (ref.node != null) return ref.asTypedef;
-
-    var t = Typedef(e.name, null, reference: ref, fileUri: e.source.uri);
-    library ??= visitLibraryElement(e.library);
-    library.addTypedef(t);
-
-    a.FunctionType type;
-    var typeParams = e.typeParameters;
-    if (e is a.GenericTypeAliasElement) {
-      type = e.function.type;
-    } else {
-      type = e.type;
-      if (typeParams.isNotEmpty) {
-        // Skip past the type formals, we'll add them back below, so these
-        // type parameter names will end up in scope in the generated JS.
-        type = type.instantiate(
-            typeParams.map((f) => getLegacyTypeParameterType(f)).toList());
-      }
-    }
-    t.typeParameters.addAll(typeParams.map(visitTypeParameterElement));
-    setParents(t.typeParameters, t);
-    t.type = _visitDartType(type, originTypedef: t.thisType);
-    _visitAnnotations(e.metadata, t.addAnnotation);
-    return t;
-  }
-
-  LibraryDependency visitImportElement(a.ImportElement e) =>
-      LibraryDependency.byReference(0, const [], _reference(e.importedLibrary),
-          null, e.combinators.map(_visitCombinator).toList());
-
-  Library visitLibraryElement(a.LibraryElement e) {
-    var ref = _reference(e);
-    if (ref.node != null) return ref.asLibrary;
-
-    var library = Library(e.source.uri,
-        name: e.name,
-        fileUri: e.definingCompilationUnit.source.uri,
-        reference: ref);
-    library.fileOffset = 0;
-
-    _visitAnnotations(e.metadata, library.addAnnotation);
-    e.imports.map(visitImportElement).forEach(library.addDependency);
-    e.exports.map(visitExportElement).forEach(library.addDependency);
-    e.parts.map((p) => LibraryPart(const [], p.uri)).forEach(library.addPart);
-
-    _visitUnit(a.CompilationUnitElement u) {
-      for (var t in u.types) {
-        visitClassElement(t, library);
-      }
-      for (var t in u.mixins) {
-        visitClassElement(t, library);
-      }
-      for (var t in u.functionTypeAliases) {
-        visitFunctionTypeAliasElement(t, library);
-      }
-      u.functions.map(visitFunctionElement).forEach(library.addMember);
-      u.accessors
-          .where((a) => !a.isSynthetic)
-          .map(visitPropertyAccessorElement)
-          .forEach(library.addMember);
-      u.topLevelVariables
-          .map(visitTopLevelVariableElement)
-          .forEach(library.addMember);
-    }
-
-    _visitUnit(e.definingCompilationUnit);
-    e.parts.forEach(_visitUnit);
-
-    var libraryImpl = e as a.LibraryElementImpl;
-    libraryImpl.publicNamespace ??=
-        _namespaceBuilder.createPublicNamespaceForLibrary(e);
-    libraryImpl.exportNamespace ??=
-        _namespaceBuilder.createExportNamespaceForLibrary(e);
-    var publicNames = libraryImpl.publicNamespace.definedNames;
-    var exportNames = libraryImpl.exportNamespace.definedNames;
-    exportNames.forEach((name, value) {
-      if (!publicNames.containsKey(name)) {
-        value = value is a.PropertyAccessorElement && value.isSynthetic
-            ? value.variable
-            : value;
-        library.additionalExports.add(_reference(value));
-      }
-    });
-    return library;
-  }
-
-  Procedure visitMethodElement(a.MethodElement e) {
-    var result = Procedure.byReference(
-        _getName(e),
-        e.isOperator ? ProcedureKind.Operator : ProcedureKind.Method,
-        _createFunction(e),
-        isAbstract: e.isAbstract,
-        isStatic: e.isStatic,
-        isExternal: e.isExternal,
-        fileUri: e.source.uri,
-        reference: _reference(e));
-    _visitAnnotations(e.metadata, result.addAnnotation);
-    return result;
-  }
-
-  Procedure visitPropertyAccessorElement(a.PropertyAccessorElement e) {
-    var result = Procedure.byReference(
-        _getName(e, e.variable.name),
-        e.isGetter ? ProcedureKind.Getter : ProcedureKind.Setter,
-        _createFunction(e),
-        isAbstract: e.isAbstract,
-        isStatic: e.isStatic,
-        isExternal: e.isExternal,
-        fileUri: e.source.uri,
-        reference: _reference(e));
-    _visitAnnotations(e.metadata, result.addAnnotation);
-    return result;
-  }
-
-  Field visitTopLevelVariableElement(a.TopLevelVariableElement e) {
-    var result = Field(_getName(e),
-        type: _visitDartType(e.type),
-        initializer: null,
-        isFinal: e.isFinal,
-        isConst: e.isConst,
-        isStatic: e.isStatic,
-        fileUri: e.source.uri,
-        reference: _reference(e));
-    _visitAnnotations(e.metadata, result.addAnnotation);
-    return result;
-  }
-
-  TypeParameter visitTypeParameterElement(a.TypeParameterElement e) {
-    var t = _typeParams[e];
-    if (t != null) return t;
-    _typeParams[e] = t = TypeParameter(e.name);
-
-    var hasBound = e.bound != null;
-    t.bound =
-        hasBound ? _visitDartType(e.bound) : _visitDartType(types.objectType);
-    t.defaultType = hasBound ? t.bound : const DynamicType();
-
-    var enclosingElement = e.enclosingElement;
-    if (hasBound && enclosingElement is a.ClassMemberElement) {
-      var class_ = enclosingElement.enclosingElement;
-      if (class_ is a.ClassElement && class_.typeParameters.isNotEmpty) {
-        t.isGenericCovariantImpl = _isGenericCovariant(class_, e.bound);
-      }
-    }
-    return t;
-  }
-
-  Name _getName(a.Element e, [String name]) {
-    name ??= e.name;
-    return Name.byReference(
-        name, name.startsWith('_') ? _reference(e.library) : null);
-  }
-
-  /// Converts an Analyzer [type] to a Kernel type.
-  ///
-  /// If [ensureNode] is set, the reference to the [Class] or [Typedef] will
-  /// populated with the node (creating it if needed). Many members on
-  /// [InterfaceType] and [TypedefType] rely on having a node present, so this
-  /// enables the use of those members if they're needed by the converter.
-  DartType _visitDartType(a.DartType type,
-      {bool ensureNode = false, TypedefType originTypedef}) {
-    if (type.isVoid) {
-      return const VoidType();
-    } else if (type.isDynamic) {
-      return const DynamicType();
-    } else if (type.isBottom) {
-      return const BottomType();
-    } else if (type is a.TypeParameterType) {
-      return TypeParameterType(visitTypeParameterElement(type.element));
-    }
-
-    visit(a.DartType t) => _visitDartType(t, ensureNode: ensureNode);
-
-    if (type is a.InterfaceType) {
-      var ref = ensureNode
-          ? visitClassElement(type.element).reference
-          : _reference(type.element);
-      var typeArgs = type.typeArguments;
-      var newTypeArgs = typeArgs.isNotEmpty
-          ? typeArgs.map(visit).toList()
-          : const <DartType>[];
-      return InterfaceType.byReference(ref, newTypeArgs);
-    }
-
-    var f = type as a.FunctionType;
-    if (f.name != null && f.name != '') {
-      var ref = ensureNode
-          ? visitFunctionTypeAliasElement(
-                  f.element as a.FunctionTypeAliasElement)
-              .reference
-          : _reference(f.element);
-      return TypedefType.byReference(ref, f.typeArguments.map(visit).toList());
-    }
-    var params = f.parameters;
-    var positional = f.normalParameterTypes.map(visit).toList();
-    positional.addAll(f.optionalParameterTypes.map(visit));
-
-    var named = <NamedType>[];
-    f.namedParameterTypes.forEach((name, type) {
-      named.add(NamedType(name, visit(type)));
-    });
-
-    return FunctionType(positional, visit(f.returnType),
-        typeParameters: f.typeFormals.map(visitTypeParameterElement).toList(),
-        namedParameters: named,
-        requiredParameterCount: params.where((p) => !p.isOptional).length,
-        typedefType: originTypedef);
-  }
-
-  Supertype _typeToSupertype(a.InterfaceType t) {
-    if (t == null) return null;
-    return Supertype(
-        visitClassElement(t.element),
-        t.typeArguments
-            .map((a) => _visitDartType(a, ensureNode: true))
-            .toList());
-  }
-
-  Combinator _visitCombinator(a.NamespaceCombinator combinator) {
-    bool isShow;
-    List<String> names;
-    if (combinator is a.ShowElementCombinator) {
-      isShow = true;
-      names = combinator.shownNames;
-    } else {
-      isShow = false;
-      names = (combinator as a.HideElementCombinator).hiddenNames;
-    }
-    return Combinator(isShow, names);
-  }
-
-  /// Creates a function node for the executable element [e], optionally using
-  /// the supplied [typeParameters] and calling [visitType] so it can perform
-  /// any necessary substitutions.
-  FunctionNode _createFunction(a.ExecutableElement e,
-      [List<TypeParameter> typeParameters,
-      DartType Function(a.DartType) visitType]) {
-    visitType ??= _visitDartType;
-
-    var enclosingElement = e.enclosingElement;
-    var class_ = enclosingElement is a.ClassElement ? enclosingElement : null;
-
-    visitParameter(a.ParameterElement e) {
-      var result = VariableDeclaration(e.name,
-          type: visitType(e.type),
-          isFinal: e.isFinal,
-          isFieldFormal: e.isInitializingFormal,
-          isCovariant: e.isCovariant,
-          initializer:
-              e.isOptional ? _visitConstant(e.computeConstantValue()) : null);
-      if (class_ != null && class_.typeParameters.isNotEmpty) {
-        result.isGenericCovariantImpl = _isGenericCovariant(class_, e.type);
-      }
-      return result;
-    }
-
-    var params = e.parameters;
-    var asyncMarker = _getAsyncMarker(e);
-    return FunctionNode(null,
-        typeParameters: typeParameters ??
-            e.typeParameters.map(visitTypeParameterElement).toList(),
-        positionalParameters:
-            params.where((p) => !p.isNamed).map(visitParameter).toList(),
-        namedParameters:
-            params.where((p) => p.isNamed).map(visitParameter).toList(),
-        requiredParameterCount: params.where((p) => !p.isOptional).length,
-        returnType: visitType(e.returnType),
-        asyncMarker: asyncMarker,
-        dartAsyncMarker: asyncMarker);
-  }
-
-  Reference _reference(a.Element e) {
-    if (e == null) throw ArgumentError('null element');
-    return _references.putIfAbsent(e, () => Reference());
-  }
-
-  bool _isGenericCovariant(a.ClassElement c, a.DartType type) {
-    var classUpperBound =
-        rules.instantiateToBounds(getLegacyRawClassType(c)) as a.InterfaceType;
-    var typeUpperBound = type.substitute2(classUpperBound.typeArguments,
-        a.TypeParameterTypeImpl.getTypes(classUpperBound.typeParameters));
-    // Is it safe to assign the upper bound of the field/parameter to it?
-    // If not then we'll need a runtime check.
-    return !rules.isSubtypeOf(typeUpperBound, type);
-  }
-
-  /// Transforms a metadata annotation from Analyzer to Kernel format.
-  ///
-  /// If needed this uses Analyzer's constant evaluation to evaluate the AST,
-  /// and then converts the resulting constant value into a Kernel tree.
-  /// By first computing the expression's constant value, we avoid having to
-  /// convert a bunch of Analyzer ASTs nodes. Instead we can convert the more
-  /// limited set of constant values allowed in Dart (see [_visitConstant]).
-  void _visitAnnotations(List<a.ElementAnnotation> metadata,
-      void Function(Expression) addAnnotation) {
-    if (metadata.isEmpty) return;
-
-    for (a.ElementAnnotation annotation in metadata) {
-      var ast = (annotation as a.ElementAnnotationImpl).annotationAst;
-      var arguments = ast.arguments;
-      if (arguments == null) {
-        var e = ast.element;
-        e = e is a.PropertyAccessorElement && e.isSynthetic ? e.variable : e;
-        addAnnotation(StaticGet.byReference(_reference(e)));
-      } else {
-        // Use Analyzer's constant evaluation to produce the constant, then
-        // emit the resulting value. We do this to avoid handling all of the
-        // AST nodes that might be needed for constant evaluation. Instead we
-        // just serialize the resulting value to a Kernel expression that will
-        // reproduce it.
-        addAnnotation(_visitConstant(annotation.computeConstantValue()));
-      }
-    }
-  }
-
-  /// Converts an Analyzer constant value in [obj] to a Kernel expression
-  /// (usually a Literal or ConstructorInvocation) that will recreate that
-  /// constant value.
-  Expression _visitConstant(a.DartObject obj) {
-    if (obj == null || obj.isNull || !obj.hasKnownValue) return NullLiteral();
-
-    var type = obj.type;
-    if (identical(type, types.boolType)) {
-      var value = obj.toBoolValue();
-      return value != null ? BoolLiteral(value) : NullLiteral();
-    }
-    if (identical(type, types.intType)) {
-      return IntLiteral(obj.toIntValue());
-    }
-    if (identical(type, types.doubleType)) {
-      return DoubleLiteral(obj.toDoubleValue());
-    }
-    if (identical(type, types.stringType)) {
-      return StringLiteral(obj.toStringValue());
-    }
-    if (identical(type, types.symbolType)) {
-      return SymbolLiteral(obj.toSymbolValue());
-    }
-    if (identical(type, types.typeType)) {
-      return TypeLiteral(_visitDartType(obj.toTypeValue()));
-    }
-    if (type is a.InterfaceType) {
-      if (type.element == types.listElement) {
-        return ListLiteral(obj.toListValue().map(_visitConstant).toList(),
-            typeArgument: _visitDartType(type.typeArguments[0]), isConst: true);
-      }
-      if (type.element == types.mapElement) {
-        var entries = obj
-            .toMapValue()
-            .entries
-            .map(
-                (e) => MapEntry(_visitConstant(e.key), _visitConstant(e.value)))
-            .toList();
-        return MapLiteral(entries,
-            keyType: _visitDartType(type.typeArguments[0]),
-            valueType: _visitDartType(type.typeArguments[1]),
-            isConst: true);
-      }
-      if (obj is a.DartObjectImpl && obj.isUserDefinedObject) {
-        var classElem = type.element;
-        if (classElem.isEnum) {
-          // TODO(jmesserly): we should be able to use `getField('index')` but
-          // in some cases Analyzer uses the name of the static field that
-          // contains the enum, rather than the `index` field, due to a bug.
-          //
-          // So we just grab the one instance field, regardless of its name.
-          var index = obj.fields.values.single.toIntValue();
-          var field =
-              classElem.fields.where((f) => f.type == type).elementAt(index);
-          return StaticGet.byReference(_reference(field));
-        }
-        var invocation = obj.getInvocation();
-        var constructor = invocation.constructor;
-        // For a redirecting const factory, the constant constructor will be
-        // from the original one, but the `type` will match the redirected type.
-        //
-        // This leads to mismatch in how we call this constructor. So we need to
-        // find the redirected one.
-        for (a.ConstructorElement rc;
-            (rc = constructor.redirectedConstructor) != null;) {
-          constructor = rc;
-        }
-        constructor = constructor is a.ConstructorMember
-            ? constructor.baseElement
-            : constructor;
-        return ConstructorInvocation.byReference(
-            _reference(constructor),
-            Arguments(
-                invocation.positionalArguments.map(_visitConstant).toList(),
-                named: invocation.namedArguments.entries
-                    .map((e) => NamedExpression(e.key, _visitConstant(e.value)))
-                    .toList(),
-                types: type.typeArguments.map(_visitDartType).toList()),
-            isConst: true);
-      }
-    }
-    if (obj is a.DartObjectImpl && type is a.FunctionType) {
-      var e = obj.toFunctionValue();
-      e = e is a.PropertyAccessorElement && e.isSynthetic
-          ? e.variable as a.ExecutableElement
-          : e;
-      // TODO(jmesserly): support generic tear-off implicit instantiation.
-      return StaticGet.byReference(_reference(e));
-    }
-    throw UnsupportedError('unknown constant type `$type`: $obj');
-  }
-}
-
-AsyncMarker _getAsyncMarker(a.ExecutableElement e) {
-  return e.isGenerator
-      ? (e.isAsynchronous ? AsyncMarker.AsyncStar : AsyncMarker.SyncStar)
-      : (e.isAsynchronous ? AsyncMarker.Async : AsyncMarker.Sync);
-}
-
-a.LinkedElementFactory _createSummaryResynthesizer(
-    a.SummaryDataStore summaryData, String dartSdkPath) {
-  var context = _createContextForSummaries(summaryData, dartSdkPath);
-
-  var elementFactory = a.LinkedElementFactory(
-    context,
-    null,
-    a.Reference.root(),
-  );
-
-  for (var bundle in summaryData.bundles) {
-    elementFactory.addBundle(
-      a.LinkedBundleContext(elementFactory, bundle.bundle2),
-    );
-  }
-
-  return elementFactory;
-}
-
-/// Creates a dummy Analyzer context so we can use summary resynthesizer.
-///
-/// This is similar to Analyzer's `LibraryContext._createResynthesizingContext`.
-a.AnalysisContextImpl _createContextForSummaries(
-    a.SummaryDataStore summaryData, String dartSdkPath) {
-  var sdk = a.SummaryBasedDartSdk(dartSdkPath, true,
-      resourceProvider: a.PhysicalResourceProvider.INSTANCE);
-  var sdkSummaryBundle = sdk.getLinkedBundle();
-  if (sdkSummaryBundle != null) {
-    summaryData.addBundle(null, sdkSummaryBundle);
-  }
-
-  // TODO(jmesserly): use RestrictedAnalysisContext.
-  var context = a.AnalysisEngine.instance.createAnalysisContext()
-      as a.AnalysisContextImpl;
-  context.sourceFactory = a.SourceFactory(
-      [a.DartUriResolver(sdk), a.InSummaryUriResolver(null, summaryData)]);
-  // TODO(jmesserly): do we need to set analysisOptions or declaredVariables?
-  return context;
-}
diff --git a/pkg/dev_compiler/lib/src/kernel/command.dart b/pkg/dev_compiler/lib/src/kernel/command.dart
index 8401522..9a92ecd 100644
--- a/pkg/dev_compiler/lib/src/kernel/command.dart
+++ b/pkg/dev_compiler/lib/src/kernel/command.dart
@@ -25,7 +25,6 @@
 import '../js_ast/js_ast.dart' show js;
 import '../js_ast/source_map_printer.dart' show SourceMapPrintingContext;
 
-import 'analyzer_to_kernel.dart';
 import 'compiler.dart';
 import 'target.dart';
 
@@ -179,14 +178,17 @@
   var summaryPaths = options.summaryModules.keys.toList();
   var summaryModules = Map.fromIterables(
       summaryPaths.map(sourcePathToUri), options.summaryModules.values);
-  var useAnalyzer = summaryPaths.any((s) => !s.endsWith('.dill'));
   var sdkSummaryPath = argResults['dart-sdk-summary'] as String;
   var librarySpecPath = argResults['libraries-file'] as String;
   if (sdkSummaryPath == null) {
-    sdkSummaryPath =
-        useAnalyzer ? defaultAnalyzerSdkSummaryPath : defaultSdkSummaryPath;
+    sdkSummaryPath = defaultSdkSummaryPath;
     librarySpecPath ??= defaultLibrarySpecPath;
   }
+  var invalidSummary = summaryPaths.any((s) => !s.endsWith('.dill')) ||
+      !sdkSummaryPath.endsWith('.dill');
+  if (invalidSummary) {
+    throw StateError("Non-dill file detected in input: $summaryPaths");
+  }
 
   if (librarySpecPath == null) {
     // TODO(jmesserly): the `isSupported` bit should be included in the SDK
@@ -205,14 +207,12 @@
     }
   }
 
-  useAnalyzer = useAnalyzer || !sdkSummaryPath.endsWith('.dill');
-
   /// The .packages file path provided by the user.
   //
   // TODO(jmesserly): the default location is based on the current working
   // directory, to match the behavior of dartanalyzer/dartdevc. However the
   // Dart VM, CFE (and dart2js?) use the script file location instead. The
-  // difference may be due to the lack of a single entry point for DDC/Analyzer.
+  // difference may be due to the lack of a single entry point for Analyzer.
   // Ultimately this is just the default behavior; in practice users call DDC
   // through a build tool, which generally passes in `--packages=`.
   //
@@ -244,7 +244,7 @@
   fe.WorkerInputComponent cachedSdkInput;
   bool recordUsedInputs = argResults['used-inputs-file'] != null;
   List<Uri> inputSummaries = summaryModules.keys.toList();
-  if (useAnalyzer || !useIncrementalCompiler) {
+  if (!useIncrementalCompiler) {
     compilerState = await fe.initializeCompiler(
         oldCompilerState,
         compileSdk,
@@ -306,15 +306,8 @@
   // `initializeCompiler`. Also we should be able to pass down Components for
   // SDK and summaries.
   //
-  if (useAnalyzer && !identical(oldCompilerState, compilerState)) {
-    var opts = compilerState.processedOpts;
-    var converter = AnalyzerToKernel(sdkSummaryPath, summaryPaths);
-    opts.sdkSummaryComponent = converter.convertSdk();
-    opts.inputSummariesComponents = converter.convertSummaries();
-  }
-
   fe.DdcResult result;
-  if (useAnalyzer || !useIncrementalCompiler) {
+  if (!useIncrementalCompiler) {
     result = await fe.compile(compilerState, inputs, diagnosticMessageHandler);
   } else {
     compilerState.options.onDiagnostic = diagnosticMessageHandler;
@@ -411,7 +404,7 @@
 
   if (recordUsedInputs) {
     Set<Uri> usedOutlines = Set<Uri>();
-    if (!useAnalyzer && useIncrementalCompiler) {
+    if (useIncrementalCompiler) {
       compilerState.incrementalCompiler
           .updateNeededDillLibrariesWithHierarchy(result.classHierarchy, null);
       for (Library lib
@@ -537,9 +530,6 @@
 
 final defaultLibrarySpecPath = p.join(getSdkPath(), 'lib', 'libraries.json');
 
-final defaultAnalyzerSdkSummaryPath =
-    p.join(getSdkPath(), 'lib', '_internal', 'ddc_sdk.sum');
-
 bool _checkForDartMirrorsImport(Component component) {
   for (var library in component.libraries) {
     if (library.isExternal || library.importUri.scheme == 'dart') continue;
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index db30dd1..d2020b3 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -45,7 +45,7 @@
   /// corresponding Kernel summary module we imported it with.
   final _importToSummary = Map<Library, Component>.identity();
 
-  /// Maps a summary to the JS import name for the module.
+  /// Maps a Kernel summary to the JS import name for the module.
   final _summaryToModule = Map<Component, String>.identity();
 
   /// The variable for the current catch clause
@@ -5491,10 +5491,10 @@
   @override
   js_ast.Expression visitPartialInstantiationConstant(
           PartialInstantiationConstant node) =>
-      runtimeCall('gbind(#, #)', [
+      canonicalizeConstObject(runtimeCall('gbind(#, #)', [
         visitConstant(node.tearOffConstant),
         node.types.map(_emitType).toList()
-      ]);
+      ]));
 
   @override
   js_ast.Expression visitUnevaluatedConstant(UnevaluatedConstant node) =>
diff --git a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
index 45efb1c..784e8a3 100644
--- a/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
+++ b/pkg/dev_compiler/lib/src/kernel/kernel_helpers.dart
@@ -252,8 +252,7 @@
 ///
 /// This is used to ignore synthetic mixin application classes.
 ///
-// TODO(jmesserly): consider replacing this with Kernel's mixin unrolling once
-// we don't have the Analyzer backend to maintain.
+// TODO(jmesserly): consider replacing this with Kernel's mixin unrolling
 Class getSuperclassAndMixins(Class c, List<Class> mixins) {
   assert(mixins.isEmpty);
 
diff --git a/pkg/dev_compiler/web/index.html b/pkg/dev_compiler/web/index.html
deleted file mode 100644
index 891bd19..0000000
--- a/pkg/dev_compiler/web/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<!DOCTYPE html>
-<html>
-  <head>
-    <meta charset="utf-8">
-    <title>Dart Dev Compiler Console</title>
-  </head>
-  <body>
-    <script defer src="main.dart.js"></script>
-  </body>
-</html>
diff --git a/pkg/dev_compiler/web/main.dart b/pkg/dev_compiler/web/main.dart
deleted file mode 100755
index b1267cb..0000000
--- a/pkg/dev_compiler/web/main.dart
+++ /dev/null
@@ -1,86 +0,0 @@
-#!/usr/bin/env dart
-// 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.
-
-@JS()
-library dev_compiler.web.main;
-
-import 'dart:async';
-
-import 'package:args/command_runner.dart';
-import 'package:js/js.dart';
-
-import 'web_command.dart';
-
-@JS(r'$setUpDartDevCompilerInBrowser')
-external set setUpCompilerInBrowser(Function function);
-
-Future<dynamic> _setUpCompilerInBrowser;
-void main() {
-  var args = ['compile'];
-
-  // Avoid race condition when users try to call $setUpDartDevCompilerInBrowser
-  // before it is ready by installing the method immediately and making the body
-  // of the method async.
-  setUpCompilerInBrowser = allowInterop((String sdkUrl,
-      JSMap<String, String> summaryMap,
-      Function onCompileReady,
-      Function onError,
-      [Function onProgress]) async {
-    (await _setUpCompilerInBrowser)(
-        sdkUrl, summaryMap, onCompileReady, onError, onProgress);
-  });
-  _runCommand(args);
-}
-
-/// Runs a single compile command, and returns an exit code.
-_runCommand(List<String> args, {MessageHandler messageHandler}) {
-  try {
-    // TODO: Remove CommandRunner and args if possible. May run into issues
-    // with ArgResults or ArgParsers.
-    var runner = CommandRunner('dartdevc', 'Dart Development Compiler');
-    runner.addCommand(WebCompileCommand(messageHandler: messageHandler));
-    _setUpCompilerInBrowser = runner.run(args);
-  } catch (e, s) {
-    _handleError(e, s, args, messageHandler: messageHandler);
-  }
-}
-
-/// Handles [error] in a uniform fashion. Calls [messageHandler] with messages.
-_handleError(dynamic error, dynamic stackTrace, List<String> args,
-    {MessageHandler messageHandler}) {
-  messageHandler ??= print;
-
-  if (error is UsageException) {
-    // Incorrect usage, input file not found, etc.
-    messageHandler(error);
-  } else if (error is CompileErrorException) {
-    // Code has error(s) and failed to compile.
-    messageHandler(error);
-  } else {
-    // Anything else is likely a compiler bug.
-    //
-    // --unsafe-force-compile is a bit of a grey area, but it's nice not to
-    // crash while compiling
-    // (of course, output code may crash, if it had errors).
-    //
-    messageHandler("");
-    messageHandler("We're sorry, you've found a bug in our compiler.");
-    messageHandler("You can report this bug at:");
-    messageHandler(
-        "    https://github.com/dart-lang/sdk/issues/labels/web-dev-compiler");
-    messageHandler("");
-    messageHandler(
-        "Please include the information below in your report, along with");
-    messageHandler(
-        "any other information that may help us track it down. Thanks!");
-    messageHandler("");
-    messageHandler("    dartdevc arguments: " + args.join(' '));
-    messageHandler("");
-    messageHandler("```");
-    messageHandler(error);
-    messageHandler(stackTrace);
-    messageHandler("```");
-  }
-}
diff --git a/pkg/dev_compiler/web/web_command.dart b/pkg/dev_compiler/web/web_command.dart
deleted file mode 100644
index e58a363..0000000
--- a/pkg/dev_compiler/web/web_command.dart
+++ /dev/null
@@ -1,313 +0,0 @@
-// Copyright (c) 2016, the Dart project authors.  Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-@JS()
-library dev_compiler.web.web_command;
-
-import 'dart:async';
-import 'dart:convert';
-import 'dart:math' as math;
-import 'dart:html' show HttpRequest;
-import 'dart:typed_data';
-
-import 'package:analyzer/file_system/file_system.dart' show ResourceUriResolver;
-import 'package:analyzer/file_system/memory_file_system.dart'
-    show MemoryResourceProvider;
-import 'package:analyzer/src/summary/idl.dart' show PackageBundle;
-import 'package:analyzer/src/summary/package_bundle_reader.dart'
-    show SummaryDataStore;
-import 'package:analyzer/src/dart/resolver/scope.dart' show Scope;
-
-import 'package:args/command_runner.dart';
-
-import 'package:dev_compiler/src/analyzer/context.dart' show AnalyzerOptions;
-import 'package:dev_compiler/src/analyzer/command.dart';
-import 'package:dev_compiler/src/analyzer/driver.dart';
-import 'package:dev_compiler/src/analyzer/module_compiler.dart';
-
-import 'package:dev_compiler/src/compiler/module_builder.dart';
-import 'package:js/js.dart';
-import 'package:path/path.dart' as p;
-
-typedef void MessageHandler(Object message);
-
-@JS()
-@anonymous
-class JSIterator<V> {}
-
-@JS('Map')
-class JSMap<K, V> {
-  external V get(K v);
-  external set(K k, V v);
-  external JSIterator<K> keys();
-  external JSIterator<V> values();
-  external int get size;
-}
-
-@JS('Array.from')
-external List<V> iteratorToList<V>(JSIterator<V> iterator);
-
-@JS()
-@anonymous
-class CompileResult {
-  external factory CompileResult(
-      {String code, List<String> errors, bool isValid});
-}
-
-typedef CompileModule(String imports, String body, String libraryName,
-    String existingLibrary, String fileName);
-
-/// The command for invoking the modular compiler.
-class WebCompileCommand extends Command {
-  @override
-  get name => 'compile';
-
-  @override
-  get description => 'Compile a set of Dart files into a JavaScript module.';
-  final MessageHandler messageHandler;
-
-  WebCompileCommand({MessageHandler messageHandler})
-      : this.messageHandler = messageHandler ?? print {
-    ddcArgParser(argParser: argParser, help: false);
-  }
-
-  @override
-  Function run() {
-    return requestSummaries;
-  }
-
-  Future<Null> requestSummaries(String sdkUrl, JSMap<String, String> summaryMap,
-      Function onCompileReady, Function onError, Function onProgress) async {
-    var sdkRequest;
-    var progress = 0;
-    // Add 1 to the count for the SDK summary.
-    var total = summaryMap.size + 1;
-    // No need to report after every  summary is loaded. Posting about 100
-    // progress updates should be more than sufficient for users to understand
-    // how long loading will take.
-    num progressDelta = math.max(total / 100, 1);
-    num nextProgressToReport = 0;
-    maybeReportProgress() {
-      if (nextProgressToReport > progress && progress != total) return;
-      nextProgressToReport += progressDelta;
-      if (onProgress != null) onProgress(progress, total);
-    }
-
-    try {
-      sdkRequest = await HttpRequest.request(sdkUrl,
-          responseType: "arraybuffer",
-          mimeType: "application/octet-stream",
-          withCredentials: true);
-    } catch (error) {
-      onError('Dart sdk summaries failed to load: $error. url: $sdkUrl');
-      return null;
-    }
-    progress++;
-    maybeReportProgress();
-
-    var sdkBytes = (sdkRequest.response as ByteBuffer).asUint8List();
-
-    // Map summary URLs to HttpRequests.
-
-    var summaryRequests =
-        iteratorToList(summaryMap.values()).map((String summaryUrl) async {
-      var request = await HttpRequest.request(summaryUrl,
-          responseType: "arraybuffer", mimeType: "application/octet-stream");
-      progress++;
-      maybeReportProgress();
-      return request;
-    }).toList();
-    try {
-      var summaryResponses = await Future.wait(summaryRequests);
-      // Map summary responses to summary bytes.
-      List<List<int>> summaryBytes = summaryResponses
-          .map((response) => (response.response as ByteBuffer).asUint8List())
-          .toList();
-      onCompileReady(setUpCompile(
-          sdkBytes, summaryBytes, iteratorToList(summaryMap.keys())));
-    } catch (error) {
-      onError('Summaries failed to load: $error');
-    }
-  }
-
-  List<Function> setUpCompile(List<int> sdkBytes, List<List<int>> summaryBytes,
-      List<String> moduleIds) {
-    var dartSdkSummaryPath = '/dart-sdk/lib/_internal/web_sdk.sum';
-
-    var resources = MemoryResourceProvider()
-      ..newFileWithBytes(dartSdkSummaryPath, sdkBytes);
-
-    var options = AnalyzerOptions.basic(
-        dartSdkPath: '/dart-sdk', dartSdkSummaryPath: dartSdkSummaryPath);
-
-    var summaryData = SummaryDataStore([], resourceProvider: resources);
-    var compilerOptions = CompilerOptions.fromArguments(argResults);
-    compilerOptions.replCompile = true;
-    compilerOptions.libraryRoot = '/';
-    for (var i = 0; i < summaryBytes.length; i++) {
-      var bytes = summaryBytes[i];
-
-      // Packages with no dart source files will have empty invalid summaries.
-      if (bytes.isEmpty) continue;
-
-      var moduleId = moduleIds[i];
-      var url = '/$moduleId.api.ds';
-      summaryData.addBundle(url, PackageBundle.fromBuffer(bytes));
-      compilerOptions.summaryModules[url] = moduleId;
-    }
-    options.analysisRoot = '/web-compile-root';
-    options.fileResolvers = [ResourceUriResolver(resources)];
-    options.resourceProvider = resources;
-
-    var driver = CompilerAnalysisDriver(options, summaryData: summaryData);
-
-    var resolveFn = (String url) {
-      var packagePrefix = 'package:';
-      var uri = Uri.parse(url);
-      var base = p.basename(url);
-      var parts = uri.pathSegments;
-      var match;
-      int bestScore = 0;
-      for (var candidate in summaryData.uriToSummaryPath.keys) {
-        if (p.basename(candidate) != base) continue;
-        List<String> candidateParts = p.dirname(candidate).split('/');
-        var first = candidateParts.first;
-
-        // Process and strip "package:" prefix.
-        if (first.startsWith(packagePrefix)) {
-          first = first.substring(packagePrefix.length);
-          candidateParts[0] = first;
-          // Handle convention that directory foo/bar/baz is given package name
-          // foo.bar.baz
-          if (first.contains('.')) {
-            candidateParts = (first.split('.'))..addAll(candidateParts.skip(1));
-          }
-        }
-
-        // If file name and extension don't match... give up.
-        int i = parts.length - 1;
-        int j = candidateParts.length - 1;
-
-        int score = 1;
-        // Greedy algorithm finding matching path segments from right to left
-        // skipping segments on the candidate path unless the target path
-        // segment is named lib.
-        while (i >= 0 && j >= 0) {
-          if (parts[i] == candidateParts[j]) {
-            i--;
-            j--;
-            score++;
-            if (j == 0 && i == 0) {
-              // Arbitrary bonus if we matched all parts of the input
-              // and used up all parts of the output.
-              score += 10;
-            }
-          } else {
-            // skip unmatched lib directories from the input
-            // otherwise skip unmatched parts of the candidate.
-            if (parts[i] == 'lib') {
-              i--;
-            } else {
-              j--;
-            }
-          }
-        }
-
-        if (score > bestScore) {
-          match = candidate;
-        }
-      }
-      return match;
-    };
-
-    CompileModule compileFn = (String imports, String body, String libraryName,
-        String existingLibrary, String fileName) {
-      // Instead of returning a single function, return a pair of functions.
-      // Create a new virtual File that contains the given Dart source.
-      String sourceCode;
-      if (existingLibrary == null) {
-        sourceCode = imports + body;
-      } else {
-        var dir = p.dirname(existingLibrary);
-        // Need to pull in all the imports from the existing library and
-        // re-export all privates as privates in this library.
-        // Assumption: summaries are available for all libraries, including any
-        // source files that were compiled; we do not need to reconstruct any
-        // summary data here.
-        var unlinked = driver.summaryData.unlinkedMap[existingLibrary];
-        if (unlinked == null) {
-          throw "Unable to get library element for `$existingLibrary`.";
-        }
-        var sb = StringBuffer(imports);
-        sb.write('\n');
-
-        // TODO(jacobr): we need to add a proper Analyzer flag specifing that
-        // cross-library privates should be in scope instead of this hack.
-        // We set the private name prefix for scope resolution to an invalid
-        // character code so that the analyzer ignores normal Dart private
-        // scoping rules for top level names allowing REPL users to access
-        // privates in arbitrary libraries. The downside of this scheme is it is
-        // possible to get errors if privates in the current library and
-        // imported libraries happen to have exactly the same name.
-        Scope.PRIVATE_NAME_PREFIX = -1;
-
-        // We emulate running code in the context of an existing library by
-        // importing that library and all libraries it imports.
-        sb.write('import ${json.encode(existingLibrary)};\n');
-
-        for (var import in unlinked.imports) {
-          if (import.uri == null || import.isImplicit) continue;
-          var uri = import.uri;
-          // dart: and package: uris are not relative but the path package
-          // thinks they are. We have to provide absolute uris as our library
-          // has a different directory than the library we are pretending to be.
-          if (p.isRelative(uri) &&
-              !uri.startsWith('package:') &&
-              !uri.startsWith('dart:')) {
-            uri = p.normalize(p.join(dir, uri));
-          }
-          sb.write('import ${json.encode(uri)}');
-          if (import.prefixReference != 0) {
-            var prefix = unlinked.references[import.prefixReference].name;
-            sb.write(' as $prefix');
-          }
-          for (var combinator in import.combinators) {
-            if (combinator.shows.isNotEmpty) {
-              sb.write(' show ${combinator.shows.join(', ')}');
-            } else if (combinator.hides.isNotEmpty) {
-              sb.write(' hide ${combinator.hides.join(', ')}');
-            } else {
-              throw 'Unexpected element combinator';
-            }
-          }
-          sb.write(';\n');
-        }
-        sb.write(body);
-        sourceCode = sb.toString();
-      }
-      resources.newFile(fileName, sourceCode);
-
-      var name = p.toUri(libraryName).toString();
-      compilerOptions.moduleName = name;
-      JSModuleFile module =
-          compileWithAnalyzer(driver, [fileName], options, compilerOptions);
-
-      var moduleCode = '';
-      if (module.isValid) {
-        moduleCode =
-            module.getCode(ModuleFormat.legacyConcat, name, name + '.map').code;
-      }
-
-      return CompileResult(
-          code: moduleCode, isValid: module.isValid, errors: module.errors);
-    };
-
-    return [allowInterop(compileFn), allowInterop(resolveFn)];
-  }
-}
-
-/// Thrown when the input source code has errors.
-class CompileErrorException implements Exception {
-  @override
-  toString() => '\nPlease fix all errors before compiling (warnings are okay).';
-}
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 b3ff558..cbd6138 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,14 +6,11 @@
 
 import 'package:kernel/ast.dart' show DartType, Nullability;
 
-import 'builder.dart'
-    show
-        LibraryBuilder,
-        NullabilityBuilder,
-        TypeBuilder,
-        TypeDeclarationBuilder;
+import 'builder.dart' show LibraryBuilder, NullabilityBuilder, TypeBuilder;
 
-abstract class BuiltinTypeBuilder extends TypeDeclarationBuilder {
+import 'type_declaration_builder.dart';
+
+abstract class BuiltinTypeBuilder extends TypeDeclarationBuilderImpl {
   final DartType type;
 
   BuiltinTypeBuilder(
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 ee0b627..936a373 100644
--- a/pkg/front_end/lib/src/fasta/builder/class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/class_builder.dart
@@ -145,7 +145,7 @@
 
 import '../type_inference/type_schema.dart' show UnknownType;
 
-abstract class ClassBuilder extends DeclarationBuilder {
+abstract class ClassBuilder implements DeclarationBuilder {
   /// The type variables declared on a class, extension or mixin declaration.
   List<TypeVariableBuilder> typeVariables;
 
@@ -161,9 +161,9 @@
   /// The types in the `on` clause of an extension or mixin declaration.
   List<TypeBuilder> onTypes;
 
-  final Scope constructors;
+  Scope get constructors;
 
-  final ScopeBuilder constructorScopeBuilder;
+  ScopeBuilder get constructorScopeBuilder;
 
   Map<String, ConstructorRedirection> redirectingConstructors;
 
@@ -171,7 +171,222 @@
 
   ClassBuilder patchForTesting;
 
-  ClassBuilder(
+  TypeBuilder get mixedInType;
+
+  void set mixedInType(TypeBuilder mixin);
+
+  List<ConstructorReferenceBuilder> get constructorReferences;
+
+  void buildOutlineExpressions(LibraryBuilder library);
+
+  /// Registers a constructor redirection for this class and returns true if
+  /// this redirection gives rise to a cycle that has not been reported before.
+  bool checkConstructorCyclic(String source, String target);
+
+  Builder 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
+  /// find a member that is known to exist and it will pick the first
+  /// declaration if the name is ambiguous.
+  ///
+  /// For example, this method is convenient for use when building synthetic
+  /// members, such as those of an enum.
+  MemberBuilder firstMemberNamed(String name);
+
+  /// The [Class] built by this builder.
+  ///
+  /// For a patch class the origin class is returned.
+  Class get cls;
+
+  // Deliberately unrelated return type to statically detect more accidental
+  // use until Builder.target is fully retired.
+  UnrelatedTarget get target;
+
+  @override
+  ClassBuilder get origin;
+
+  Class get actualCls;
+
+  InterfaceType get legacyRawType;
+
+  InterfaceType get nullableRawType;
+
+  InterfaceType get nonNullableRawType;
+
+  InterfaceType rawType(Nullability nullability);
+
+  List<DartType> buildTypeArguments(
+      LibraryBuilder library, List<TypeBuilder> arguments);
+
+  Supertype buildSupertype(LibraryBuilder library, List<TypeBuilder> arguments);
+
+  Supertype buildMixedInType(
+      LibraryBuilder library, List<TypeBuilder> arguments);
+
+  void checkSupertypes(CoreTypes coreTypes);
+
+  void checkBoundsInSupertype(
+      Supertype supertype, TypeEnvironment typeEnvironment);
+
+  void checkBoundsInOutline(TypeEnvironment typeEnvironment);
+
+  void addRedirectingConstructor(
+      ProcedureBuilder constructorBuilder, SourceLibraryBuilder library);
+
+  void handleSeenCovariant(
+      Types types,
+      Member declaredMember,
+      Member interfaceMember,
+      bool isSetter,
+      callback(Member declaredMember, Member interfaceMember, bool isSetter));
+
+  void checkOverride(
+      Types types,
+      Member declaredMember,
+      Member interfaceMember,
+      bool isSetter,
+      callback(Member declaredMember, Member interfaceMember, bool isSetter),
+      {bool isInterfaceCheck = false});
+
+  void checkOverrides(
+      ClassHierarchy hierarchy, TypeEnvironment typeEnvironment);
+
+  void checkAbstractMembers(CoreTypes coreTypes, ClassHierarchy hierarchy,
+      TypeEnvironment typeEnvironment);
+
+  bool hasUserDefinedNoSuchMethod(
+      Class klass, ClassHierarchy hierarchy, Class objectClass);
+
+  void transformProcedureToNoSuchMethodForwarder(
+      Member noSuchMethodInterface, KernelTarget target, Procedure procedure);
+
+  void addNoSuchMethodForwarderForProcedure(Member noSuchMethod,
+      KernelTarget target, Procedure procedure, ClassHierarchy hierarchy);
+
+  void addNoSuchMethodForwarderGetterForField(Member noSuchMethod,
+      KernelTarget target, Field field, ClassHierarchy hierarchy);
+
+  void addNoSuchMethodForwarderSetterForField(Member noSuchMethod,
+      KernelTarget target, Field field, ClassHierarchy hierarchy);
+
+  /// Adds noSuchMethod forwarding stubs to this class. Returns `true` if the
+  /// class was modified.
+  bool addNoSuchMethodForwarders(KernelTarget target, ClassHierarchy hierarchy);
+
+  /// Returns whether a covariant parameter was seen and more methods thus have
+  /// to be checked.
+  bool checkMethodOverride(Types types, Procedure declaredMember,
+      Procedure interfaceMember, bool isInterfaceCheck);
+
+  void checkGetterOverride(Types types, Member declaredMember,
+      Member interfaceMember, bool isInterfaceCheck);
+
+  /// Returns whether a covariant parameter was seen and more methods thus have
+  /// to be checked.
+  bool checkSetterOverride(Types types, Member declaredMember,
+      Member interfaceMember, bool isInterfaceCheck);
+
+  // When the overriding member is inherited, report the class containing
+  // the conflict as the main error.
+  void reportInvalidOverride(bool isInterfaceCheck, Member declaredMember,
+      Message message, int fileOffset, int length,
+      {List<LocatedMessage> context});
+
+  void checkMixinApplication(ClassHierarchy hierarchy);
+
+  // Computes the function type of a given redirection target. Returns [null] if
+  // the type of the target could not be computed.
+  FunctionType computeRedirecteeType(
+      RedirectingFactoryBuilder factory, TypeEnvironment typeEnvironment);
+
+  String computeRedirecteeName(ConstructorReferenceBuilder redirectionTarget);
+
+  void checkRedirectingFactory(
+      RedirectingFactoryBuilder factory, TypeEnvironment typeEnvironment);
+
+  void checkRedirectingFactories(TypeEnvironment typeEnvironment);
+
+  /// Returns a map which maps the type variables of [superclass] to their
+  /// respective values as defined by the superclass clause of this class (and
+  /// its superclasses).
+  ///
+  /// It's assumed that [superclass] is a superclass of this class.
+  ///
+  /// For example, given:
+  ///
+  ///     class Box<T> {}
+  ///     class BeatBox extends Box<Beat> {}
+  ///     class Beat {}
+  ///
+  /// We have:
+  ///
+  ///     [[BeatBox]].getSubstitutionMap([[Box]]) -> {[[Box::T]]: Beat]]}.
+  ///
+  /// It's an error if [superclass] isn't a superclass.
+  Map<TypeParameter, DartType> getSubstitutionMap(Class superclass);
+
+  /// Looks up the member by [name] on the class built by this class builder.
+  ///
+  /// If [isSetter] is `false`, only fields, methods, and getters with that name
+  /// will be found.  If [isSetter] is `true`, only non-final fields and setters
+  /// will be found.
+  ///
+  /// If [isSuper] is `false`, the member is found among the interface members
+  /// the class built by this class builder. If [isSuper] is `true`, the member
+  /// is found among the class members of the superclass.
+  ///
+  /// If this class builder is a patch, interface members declared in this
+  /// patch are searched before searching the interface members in the origin
+  /// class.
+  Member lookupInstanceMember(ClassHierarchy hierarchy, Name name,
+      {bool isSetter: false, bool isSuper: false});
+
+  /// Looks up the constructor by [name] on the the class built by this class
+  /// builder.
+  ///
+  /// If [isSuper] is `true`, constructors in the superclass are searched.
+  Constructor lookupConstructor(Name name, {bool isSuper: false});
+}
+
+abstract class ClassBuilderImpl extends DeclarationBuilderImpl
+    implements ClassBuilder {
+  @override
+  List<TypeVariableBuilder> typeVariables;
+
+  @override
+  TypeBuilder supertype;
+
+  @override
+  List<TypeBuilder> interfaces;
+
+  @override
+  List<TypeBuilder> onTypes;
+
+  @override
+  final Scope constructors;
+
+  @override
+  final ScopeBuilder constructorScopeBuilder;
+
+  @override
+  Map<String, ConstructorRedirection> redirectingConstructors;
+
+  @override
+  ClassBuilder actualOrigin;
+
+  @override
+  ClassBuilder patchForTesting;
+
+  ClassBuilderImpl(
       List<MetadataBuilder> metadata,
       int modifiers,
       String name,
@@ -186,10 +401,10 @@
       : constructorScopeBuilder = new ScopeBuilder(constructors),
         super(metadata, modifiers, name, parent, charOffset, scope);
 
+  @override
   String get debugName => "ClassBuilder";
 
-  /// Returns true if this class is the result of applying a mixin to its
-  /// superclass.
+  @override
   bool get isMixinApplication => mixedInType != null;
 
   @override
@@ -197,12 +412,10 @@
     return isMixinApplication && super.isNamedMixinApplication;
   }
 
-  TypeBuilder get mixedInType;
-
-  void set mixedInType(TypeBuilder mixin);
-
+  @override
   List<ConstructorReferenceBuilder> get constructorReferences => null;
 
+  @override
   void buildOutlineExpressions(LibraryBuilder library) {
     void build(String ignore, Builder declaration) {
       MemberBuilder member = declaration;
@@ -323,7 +536,6 @@
     return count;
   }
 
-  /// Used to lookup a static member of this class.
   @override
   Builder findStaticBuilder(
       String name, int charOffset, Uri fileUri, LibraryBuilder accessingLibrary,
@@ -342,6 +554,7 @@
     return declaration;
   }
 
+  @override
   Builder findConstructorOrFactory(
       String name, int charOffset, Uri uri, LibraryBuilder accessingLibrary) {
     if (accessingLibrary.origin != library.origin && name.startsWith("_")) {
@@ -355,6 +568,7 @@
     return declaration;
   }
 
+  @override
   void forEach(void f(String name, Builder builder)) {
     scope.forEach(f);
   }
@@ -376,14 +590,7 @@
     return builder;
   }
 
-  /// 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
-  /// find a member that is known to exist and it will pick the first
-  /// declaration if the name is ambiguous.
-  ///
-  /// For example, this method is convenient for use when building synthetic
-  /// members, such as those of an enum.
+  @override
   MemberBuilder firstMemberNamed(String name) {
     Builder declaration = lookupLocalMember(name, required: true);
     while (declaration.next != null) {
@@ -392,31 +599,26 @@
     return declaration;
   }
 
-  /// The [Class] built by this builder.
-  ///
-  /// For a patch class the origin class is returned.
-  Class get cls;
-
   InterfaceType _legacyRawType;
   InterfaceType _nullableRawType;
   InterfaceType _nonNullableRawType;
 
   // Deliberately unrelated return type to statically detect more accidental
   // use until Builder.target is fully retired.
+  @override
   UnrelatedTarget get target => unsupported(
       "ClassBuilder.target is deprecated. "
       "Use ClassBuilder.cls instead.",
       charOffset,
       fileUri);
 
-  Class get actualCls;
-
   @override
   ClassBuilder get origin => actualOrigin ?? this;
 
   @override
   InterfaceType get thisType => cls.thisType;
 
+  @override
   InterfaceType get legacyRawType {
     // TODO(dmitryas): Use computeBound instead of DynamicType here?
     return _legacyRawType ??= new InterfaceType(
@@ -425,6 +627,7 @@
         Nullability.legacy);
   }
 
+  @override
   InterfaceType get nullableRawType {
     // TODO(dmitryas): Use computeBound instead of DynamicType here?
     return _nullableRawType ??= new InterfaceType(
@@ -433,6 +636,7 @@
         Nullability.nullable);
   }
 
+  @override
   InterfaceType get nonNullableRawType {
     // TODO(dmitryas): Use computeBound instead of DynamicType here?
     return _nonNullableRawType ??= new InterfaceType(
@@ -441,6 +645,7 @@
         Nullability.nonNullable);
   }
 
+  @override
   InterfaceType rawType(Nullability nullability) {
     switch (nullability) {
       case Nullability.legacy:
@@ -455,7 +660,7 @@
     }
   }
 
-  /// [arguments] have already been built.
+  @override
   InterfaceType buildTypesWithBuiltArguments(LibraryBuilder library,
       Nullability nullability, List<DartType> arguments) {
     assert(arguments == null || cls.typeParameters.length == arguments.length);
@@ -467,6 +672,7 @@
   @override
   int get typeVariablesCount => typeVariables?.length ?? 0;
 
+  @override
   List<DartType> buildTypeArguments(
       LibraryBuilder library, List<TypeBuilder> arguments) {
     if (arguments == null && typeVariables == null) {
@@ -505,7 +711,7 @@
     return result;
   }
 
-  /// If [arguments] are null, the default types for the variables are used.
+  @override
   InterfaceType buildType(LibraryBuilder library,
       NullabilityBuilder nullabilityBuilder, List<TypeBuilder> arguments) {
     return buildTypesWithBuiltArguments(
@@ -514,12 +720,14 @@
         buildTypeArguments(library, arguments));
   }
 
+  @override
   Supertype buildSupertype(
       LibraryBuilder library, List<TypeBuilder> arguments) {
     Class cls = isPatch ? origin.cls : this.cls;
     return new Supertype(cls, buildTypeArguments(library, arguments));
   }
 
+  @override
   Supertype buildMixedInType(
       LibraryBuilder library, List<TypeBuilder> arguments) {
     Class cls = isPatch ? origin.cls : this.cls;
@@ -534,6 +742,7 @@
     }
   }
 
+  @override
   void checkSupertypes(CoreTypes coreTypes) {
     // This method determines whether the class (that's being built) its super
     // class appears both in 'extends' and 'implements' clauses and whether any
@@ -593,6 +802,7 @@
     }
   }
 
+  @override
   void checkBoundsInSupertype(
       Supertype supertype, TypeEnvironment typeEnvironment) {
     SourceLibraryBuilder library = this.library;
@@ -642,6 +852,7 @@
     }
   }
 
+  @override
   void checkBoundsInOutline(TypeEnvironment typeEnvironment) {
     SourceLibraryBuilder library = this.library;
 
@@ -716,6 +927,7 @@
     }
   }
 
+  @override
   void addRedirectingConstructor(
       ProcedureBuilder constructorBuilder, SourceLibraryBuilder library) {
     // Add a new synthetic field to this class for representing factory
@@ -746,6 +958,7 @@
         .add(new StaticGet(constructorBuilder.procedure)..parent = literal);
   }
 
+  @override
   void handleSeenCovariant(
       Types types,
       Member declaredMember,
@@ -763,6 +976,7 @@
     }
   }
 
+  @override
   void checkOverride(
       Types types,
       Member declaredMember,
@@ -830,18 +1044,22 @@
     // TODO(ahe): Handle other cases: accessors, operators, and fields.
   }
 
+  @override
   void checkOverrides(
       ClassHierarchy hierarchy, TypeEnvironment typeEnvironment) {}
 
+  @override
   void checkAbstractMembers(CoreTypes coreTypes, ClassHierarchy hierarchy,
       TypeEnvironment typeEnvironment) {}
 
+  @override
   bool hasUserDefinedNoSuchMethod(
       Class klass, ClassHierarchy hierarchy, Class objectClass) {
     Member noSuchMethod = hierarchy.getDispatchTarget(klass, noSuchMethodName);
     return noSuchMethod != null && noSuchMethod.enclosingClass != objectClass;
   }
 
+  @override
   void transformProcedureToNoSuchMethodForwarder(
       Member noSuchMethodInterface, KernelTarget target, Procedure procedure) {
     String prefix =
@@ -871,6 +1089,7 @@
     procedure.isForwardingSemiStub = false;
   }
 
+  @override
   void addNoSuchMethodForwarderForProcedure(Member noSuchMethod,
       KernelTarget target, Procedure procedure, ClassHierarchy hierarchy) {
     CloneWithoutBody cloner = new CloneWithoutBody(
@@ -887,6 +1106,7 @@
     library.forwardersOrigins.add(procedure);
   }
 
+  @override
   void addNoSuchMethodForwarderGetterForField(Member noSuchMethod,
       KernelTarget target, Field field, ClassHierarchy hierarchy) {
     Substitution substitution = Substitution.fromSupertype(
@@ -907,6 +1127,7 @@
     getter.parent = cls;
   }
 
+  @override
   void addNoSuchMethodForwarderSetterForField(Member noSuchMethod,
       KernelTarget target, Field field, ClassHierarchy hierarchy) {
     Substitution substitution = Substitution.fromSupertype(
@@ -930,8 +1151,7 @@
     setter.parent = cls;
   }
 
-  /// Adds noSuchMethod forwarding stubs to this class. Returns `true` if the
-  /// class was modified.
+  @override
   bool addNoSuchMethodForwarders(
       KernelTarget target, ClassHierarchy hierarchy) {
     if (cls.isAbstract) return false;
@@ -1225,8 +1445,7 @@
     }
   }
 
-  /// Returns whether a covariant parameter was seen and more methods thus have
-  /// to be checked.
+  @override
   bool checkMethodOverride(Types types, Procedure declaredMember,
       Procedure interfaceMember, bool isInterfaceCheck) {
     assert(declaredMember.kind == ProcedureKind.Method);
@@ -1417,8 +1636,7 @@
         isInterfaceCheck);
   }
 
-  /// Returns whether a covariant parameter was seen and more methods thus have
-  /// to be checked.
+  @override
   bool checkSetterOverride(Types types, Member declaredMember,
       Member interfaceMember, bool isInterfaceCheck) {
     Substitution interfaceSubstitution = _computeInterfaceSubstitution(
@@ -1451,8 +1669,7 @@
     return isCovariant;
   }
 
-  // When the overriding member is inherited, report the class containing
-  // the conflict as the main error.
+  @override
   void reportInvalidOverride(bool isInterfaceCheck, Member declaredMember,
       Message message, int fileOffset, int length,
       {List<LocatedMessage> context}) {
@@ -1501,12 +1718,14 @@
     }
   }
 
+  @override
   String get fullNameForErrors {
     return isMixinApplication && !isNamedMixinApplication
         ? "${supertype.fullNameForErrors} with ${mixedInType.fullNameForErrors}"
         : name;
   }
 
+  @override
   void checkMixinApplication(ClassHierarchy hierarchy) {
     // A mixin declaration can only be applied to a class that implements all
     // the declaration's superclass constraints.
@@ -1576,8 +1795,7 @@
     }
   }
 
-  // Computes the function type of a given redirection target. Returns [null] if
-  // the type of the target could not be computed.
+  @override
   FunctionType computeRedirecteeType(
       RedirectingFactoryBuilder factory, TypeEnvironment typeEnvironment) {
     ConstructorReferenceBuilder redirectionTarget = factory.redirectionTarget;
@@ -1673,6 +1891,7 @@
     return hasProblem ? null : targetFunctionType;
   }
 
+  @override
   String computeRedirecteeName(ConstructorReferenceBuilder redirectionTarget) {
     String targetName = redirectionTarget.fullNameForErrors;
     if (targetName == "") {
@@ -1682,6 +1901,7 @@
     }
   }
 
+  @override
   void checkRedirectingFactory(
       RedirectingFactoryBuilder factory, TypeEnvironment typeEnvironment) {
     // The factory type cannot contain any type parameters other than those of
@@ -1707,6 +1927,7 @@
     }
   }
 
+  @override
   void checkRedirectingFactories(TypeEnvironment typeEnvironment) {
     Map<String, MemberBuilder> constructors = this.constructors.local;
     Iterable<String> names = constructors.keys;
@@ -1721,23 +1942,7 @@
     }
   }
 
-  /// Returns a map which maps the type variables of [superclass] to their
-  /// respective values as defined by the superclass clause of this class (and
-  /// its superclasses).
-  ///
-  /// It's assumed that [superclass] is a superclass of this class.
-  ///
-  /// For example, given:
-  ///
-  ///     class Box<T> {}
-  ///     class BeatBox extends Box<Beat> {}
-  ///     class Beat {}
-  ///
-  /// We have:
-  ///
-  ///     [[BeatBox]].getSubstitutionMap([[Box]]) -> {[[Box::T]]: Beat]]}.
-  ///
-  /// It's an error if [superclass] isn't a superclass.
+  @override
   Map<TypeParameter, DartType> getSubstitutionMap(Class superclass) {
     Supertype supertype = cls.supertype;
     Map<TypeParameter, DartType> substitutionMap = <TypeParameter, DartType>{};
@@ -1771,19 +1976,7 @@
     return substitutionMap;
   }
 
-  /// Looks up the member by [name] on the class built by this class builder.
-  ///
-  /// If [isSetter] is `false`, only fields, methods, and getters with that name
-  /// will be found.  If [isSetter] is `true`, only non-final fields and setters
-  /// will be found.
-  ///
-  /// If [isSuper] is `false`, the member is found among the interface members
-  /// the class built by this class builder. If [isSuper] is `true`, the member
-  /// is found among the class members of the superclass.
-  ///
-  /// If this class builder is a patch, interface members declared in this
-  /// patch are searched before searching the interface members in the origin
-  /// class.
+  @override
   Member lookupInstanceMember(ClassHierarchy hierarchy, Name name,
       {bool isSetter: false, bool isSuper: false}) {
     Class instanceClass = cls;
@@ -1824,10 +2017,7 @@
     return target;
   }
 
-  /// Looks up the constructor by [name] on the the class built by this class
-  /// builder.
-  ///
-  /// If [isSuper] is `true`, constructors in the superclass are searched.
+  @override
   Constructor lookupConstructor(Name name, {bool isSuper: false}) {
     Class instanceClass = cls;
     if (isSuper) {
diff --git a/pkg/front_end/lib/src/fasta/builder/declaration.dart b/pkg/front_end/lib/src/fasta/builder/declaration.dart
index e2c75dc..01043a0 100644
--- a/pkg/front_end/lib/src/fasta/builder/declaration.dart
+++ b/pkg/front_end/lib/src/fasta/builder/declaration.dart
@@ -15,33 +15,31 @@
   /// block scopes.
   Builder next;
 
-  Builder();
-
   Builder get parent;
 
   Uri get fileUri;
 
   int get charOffset;
 
-  get target => unsupported("${runtimeType}.target", charOffset, fileUri);
+  get target;
 
-  Builder get origin => this;
+  Builder get origin;
 
   String get fullNameForErrors;
 
-  bool get hasProblem => false;
+  bool get hasProblem;
 
-  bool get isConst => false;
+  bool get isConst;
 
-  bool get isConstructor => false;
+  bool get isConstructor;
 
-  bool get isFactory => false;
+  bool get isFactory;
 
-  bool get isField => false;
+  bool get isField;
 
-  bool get isFinal => false;
+  bool get isFinal;
 
-  bool get isGetter => false;
+  bool get isGetter;
 
   /// Returns `true` if this builder is an extension declaration.
   ///
@@ -50,7 +48,7 @@
   ///    class A {}
   ///    extension B on A {}
   ///
-  bool get isExtension => false;
+  bool get isExtension;
 
   /// Returns `true` if this builder is a member of a class, mixin, or extension
   /// declaration.
@@ -72,7 +70,7 @@
   ///       static method3b() {}
   ///     }
   ///
-  bool get isDeclarationMember => false;
+  bool get isDeclarationMember;
 
   /// Returns `true` if this builder is a member of a class or mixin
   /// declaration.
@@ -94,7 +92,7 @@
   ///       static method3b() {} // Not a class member.
   ///     }
   ///
-  bool get isClassMember => false;
+  bool get isClassMember;
 
   /// Returns `true` if this builder is a member of an extension declaration.
   ///
@@ -114,7 +112,7 @@
   ///       static method3b() {}
   ///     }
   ///
-  bool get isExtensionMember => false;
+  bool get isExtensionMember;
 
   /// Returns `true` if this builder is an instance member of a class, mixin, or
   /// extension declaration.
@@ -135,7 +133,7 @@
   ///       static method3b() {} // Not a declaration instance member.
   ///     }
   ///
-  bool get isDeclarationInstanceMember => false;
+  bool get isDeclarationInstanceMember;
 
   /// Returns `true` if this builder is an instance member of a class or mixin
   /// extension declaration.
@@ -156,7 +154,7 @@
   ///       static method3b() {} // Not a class instance member.
   ///     }
   ///
-  bool get isClassInstanceMember => false;
+  bool get isClassInstanceMember;
 
   /// Returns `true` if this builder is an instance member of an extension
   /// declaration.
@@ -177,47 +175,153 @@
   ///       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;
   }
 
-  /// Applies [patch] to this declaration.
+  @override
   void applyPatch(Builder patch) {
     unsupported("${runtimeType}.applyPatch", charOffset, fileUri);
   }
 
-  /// Returns the number of patches that was finished.
+  @override
   int finishPatch() {
     if (!isPatch) return 0;
     unsupported("${runtimeType}.finishPatch", charOffset, fileUri);
     return 0;
   }
 
-  /// Resolve constructors (lookup names in scope) recorded in this builder and
-  /// return the number of constructors resolved.
+  @override
   int resolveConstructors(covariant Builder parent) => 0;
+
+  @override
+  bool get isDuplicate => next != null;
 }
diff --git a/pkg/front_end/lib/src/fasta/builder/declaration_builder.dart b/pkg/front_end/lib/src/fasta/builder/declaration_builder.dart
index bc61309..01d9fb0 100644
--- a/pkg/front_end/lib/src/fasta/builder/declaration_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/declaration_builder.dart
@@ -14,20 +14,12 @@
 import 'metadata_builder.dart';
 import 'type_declaration_builder.dart';
 
-abstract class DeclarationBuilder extends TypeDeclarationBuilder {
-  final Scope scope;
+abstract class DeclarationBuilder implements TypeDeclarationBuilder {
+  Scope get scope;
 
-  final ScopeBuilder scopeBuilder;
+  ScopeBuilder get scopeBuilder;
 
-  DeclarationBuilder(List<MetadataBuilder> metadata, int modifiers, String name,
-      LibraryBuilder parent, int charOffset, this.scope)
-      : scopeBuilder = new ScopeBuilder(scope),
-        super(metadata, modifiers, name, parent, charOffset);
-
-  LibraryBuilder get library {
-    LibraryBuilder library = parent;
-    return library.partOfLibrary ?? library;
-  }
+  LibraryBuilder get library;
 
   /// Lookup a member accessed statically through this declaration.
   Builder findStaticBuilder(
@@ -35,10 +27,7 @@
       {bool isSetter: false});
 
   void addProblem(Message message, int charOffset, int length,
-      {bool wasHandled: false, List<LocatedMessage> context}) {
-    library.addProblem(message, charOffset, length, fileUri,
-        wasHandled: wasHandled, context: context);
-  }
+      {bool wasHandled: false, List<LocatedMessage> context});
 
   /// Returns the type of `this` in an instance of this declaration.
   ///
@@ -54,3 +43,30 @@
   Builder lookupLocalMember(String name,
       {bool setter: false, bool required: false});
 }
+
+abstract class DeclarationBuilderImpl extends TypeDeclarationBuilderImpl
+    implements DeclarationBuilder {
+  @override
+  final Scope scope;
+
+  @override
+  final ScopeBuilder scopeBuilder;
+
+  DeclarationBuilderImpl(List<MetadataBuilder> metadata, int modifiers,
+      String name, LibraryBuilder parent, int charOffset, this.scope)
+      : scopeBuilder = new ScopeBuilder(scope),
+        super(metadata, modifiers, name, parent, charOffset);
+
+  @override
+  LibraryBuilder get library {
+    LibraryBuilder library = parent;
+    return library.partOfLibrary ?? library;
+  }
+
+  @override
+  void addProblem(Message message, int charOffset, int length,
+      {bool wasHandled: false, List<LocatedMessage> context}) {
+    library.addProblem(message, charOffset, length, fileUri,
+        wasHandled: wasHandled, context: context);
+  }
+}
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 dc2007f..f26fded 100644
--- a/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/extension_builder.dart
@@ -17,11 +17,30 @@
 import 'type_builder.dart';
 import 'type_variable_builder.dart';
 
-abstract class ExtensionBuilder extends DeclarationBuilder {
+abstract class ExtensionBuilder implements DeclarationBuilder {
+  List<TypeVariableBuilder> get typeParameters;
+  TypeBuilder get onType;
+
+  /// Return the [Extension] built by this builder.
+  Extension get extension;
+
+  // Deliberately unrelated return type to statically detect more accidental
+  // use until Builder.target is fully retired.
+  @override
+  UnrelatedTarget get target;
+
+  void buildOutlineExpressions(LibraryBuilder library);
+}
+
+abstract class ExtensionBuilderImpl extends DeclarationBuilderImpl
+    implements ExtensionBuilder {
+  @override
   final List<TypeVariableBuilder> typeParameters;
+
+  @override
   final TypeBuilder onType;
 
-  ExtensionBuilder(
+  ExtensionBuilderImpl(
       List<MetadataBuilder> metadata,
       int modifiers,
       String name,
@@ -32,10 +51,8 @@
       this.onType)
       : super(metadata, modifiers, name, parent, charOffset, scope);
 
-  /// Return the [Extension] built by this builder.
-  Extension get extension;
-
   /// Lookup a static member of this declaration.
+  @override
   Builder findStaticBuilder(
       String name, int charOffset, Uri fileUri, LibraryBuilder accessingLibrary,
       {bool isSetter: false}) {
@@ -51,6 +68,7 @@
 
   // Deliberately unrelated return type to statically detect more accidental
   // use until Builder.target is fully retired.
+  @override
   UnrelatedTarget get target => unsupported(
       "ExtensionBuilder.target is deprecated. "
       "Use ExtensionBuilder.extension instead.",
@@ -94,6 +112,7 @@
   @override
   String get debugName => "ExtensionBuilder";
 
+  @override
   void buildOutlineExpressions(LibraryBuilder library) {
     void build(String ignore, Builder declaration) {
       MemberBuilder member = declaration;
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 6ef5385..93fd797 100644
--- a/pkg/front_end/lib/src/fasta/builder/field_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/field_builder.dart
@@ -6,7 +6,9 @@
 
 import 'package:kernel/ast.dart' show DartType, Expression;
 
-import 'builder.dart' show LibraryBuilder, MemberBuilder;
+import 'builder.dart' show LibraryBuilder;
+
+import 'member_builder.dart';
 
 import 'package:kernel/ast.dart'
     show
@@ -57,7 +59,7 @@
 
 import 'extension_builder.dart';
 
-class FieldBuilder extends MemberBuilder {
+class FieldBuilder extends MemberBuilderImpl {
   final String name;
 
   final int modifiers;
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 44e5a9a..e2f6380 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
@@ -12,8 +12,9 @@
         isOptionalNamedFormalParameterKind,
         isOptionalPositionalFormalParameterKind;
 
-import 'builder.dart'
-    show LibraryBuilder, MetadataBuilder, ModifierBuilder, TypeBuilder;
+import 'builder.dart' show LibraryBuilder, MetadataBuilder, TypeBuilder;
+
+import 'modifier_builder.dart';
 
 import 'package:kernel/ast.dart' show VariableDeclaration;
 
@@ -45,7 +46,7 @@
 
 /// A builder for a formal parameter, i.e. a parameter on a method or
 /// constructor.
-class FormalParameterBuilder extends ModifierBuilder {
+class FormalParameterBuilder extends ModifierBuilderImpl {
   /// List of metadata builders for the metadata declared on this parameter.
   final List<MetadataBuilder> metadata;
 
diff --git a/pkg/front_end/lib/src/fasta/builder/invalid_type_builder.dart b/pkg/front_end/lib/src/fasta/builder/invalid_type_builder.dart
index c03cc7d..58a8d5a 100644
--- a/pkg/front_end/lib/src/fasta/builder/invalid_type_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/invalid_type_builder.dart
@@ -8,11 +8,13 @@
 
 import '../fasta_codes.dart' show LocatedMessage;
 
-import 'builder.dart' show NullabilityBuilder, TypeDeclarationBuilder;
+import 'builder.dart' show NullabilityBuilder;
 
 import '../kernel/kernel_builder.dart' show TypeBuilder, LibraryBuilder;
 
-class InvalidTypeBuilder extends TypeDeclarationBuilder {
+import 'type_declaration_builder.dart';
+
+class InvalidTypeBuilder extends TypeDeclarationBuilderImpl {
   String get debugName => "InvalidTypeBuilder";
 
   final LocatedMessage message;
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 71093d5..528422f 100644
--- a/pkg/front_end/lib/src/fasta/builder/library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/library_builder.dart
@@ -30,6 +30,7 @@
         ClassBuilder,
         Builder,
         FieldBuilder,
+        MemberBuilder,
         ModifierBuilder,
         NameIterator,
         NullabilityBuilder,
@@ -40,30 +41,190 @@
 
 import 'declaration.dart';
 
-abstract class LibraryBuilder extends ModifierBuilder {
-  final Scope scope;
+import 'modifier_builder.dart';
 
-  final Scope exportScope;
+abstract class LibraryBuilder implements ModifierBuilder {
+  Scope get scope;
 
-  final ScopeBuilder scopeBuilder;
+  Scope get exportScope;
 
-  final ScopeBuilder exportScopeBuilder;
+  ScopeBuilder get scopeBuilder;
 
-  final List<Export> exporters = <Export>[];
+  ScopeBuilder get exportScopeBuilder;
+
+  List<Export> get exporters;
 
   LibraryBuilder partOfLibrary;
 
+  bool mayImplementRestrictedTypes;
+
+  // Deliberately unrelated return type to statically detect more accidental
+  // use until Builder.target is fully retired.
+  @override
+  UnrelatedTarget get target;
+
+  /// Set the langauge 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
+  /// ignored.
+  /// Multiple calls with [explicit] set to false should be allowed though.
+  ///
+  /// The main idea is that the .packages file specifies a default language
+  /// version, but that the library can have source code that specifies another
+  /// one which should be supported, but specifying several in code should not
+  /// change anything.
+  ///
+  /// [offset] and [length] refers to the offset and length of the source code
+  /// specifying the language version.
+  void setLanguageVersion(int major, int minor,
+      {int offset: 0, int length, bool explicit});
+
+  bool get isPart;
+
+  Loader get loader;
+
+  /// Returns the [Library] built by this builder.
+  Library get library;
+
+  /// Returns the import uri for the library.
+  ///
+  /// This is the canonical uri for the library, for instance 'dart:core'.
+  Uri get uri;
+
+  Iterator<Builder> get iterator;
+
+  NameIterator get nameIterator;
+
+  Builder addBuilder(String name, Builder declaration, int charOffset);
+
+  void addExporter(
+      LibraryBuilder exporter, List<Combinator> combinators, int charOffset);
+
+  /// Add a problem with a severity determined by the severity of the message.
+  ///
+  /// If [fileUri] is null, it defaults to `this.fileUri`.
+  ///
+  /// See `Loader.addMessage` for an explanation of the
+  /// arguments passed to this method.
+  FormattedMessage addProblem(
+      Message message, int charOffset, int length, Uri fileUri,
+      {bool wasHandled: false,
+      List<LocatedMessage> context,
+      Severity severity,
+      bool problemOnLibrary: false});
+
+  /// Returns true if the export scope was modified.
+  bool addToExportScope(String name, Builder member, [int charOffset = -1]);
+
+  void addToScope(String name, Builder member, int charOffset, bool isImport);
+
+  Builder computeAmbiguousDeclaration(
+      String name, Builder declaration, Builder other, int charOffset,
+      {bool isExport: false, bool isImport: false});
+
+  int finishDeferredLoadTearoffs();
+
+  int finishForwarders();
+
+  int finishNativeMethods();
+
+  int finishPatchMethods();
+
+  /// Looks up [constructorName] in the class named [className].
+  ///
+  /// The class is looked up in this library's export scope unless
+  /// [bypassLibraryPrivacy] is true, in which case it is looked up in the
+  /// library scope of this library.
+  ///
+  /// It is an error if no such class is found, or if the class doesn't have a
+  /// matching constructor (or factory).
+  ///
+  /// If [constructorName] is null or the empty string, it's assumed to be an
+  /// unnamed constructor. it's an error if [constructorName] starts with
+  /// `"_"`, and [bypassLibraryPrivacy] is false.
+  MemberBuilder getConstructor(String className,
+      {String constructorName, bool bypassLibraryPrivacy: false});
+
+  int finishTypeVariables(ClassBuilder object, TypeBuilder dynamicType);
+
+  /// This method instantiates type parameters to their bounds in some cases
+  /// where they were omitted by the programmer and not provided by the type
+  /// inference.  The method returns the number of distinct type variables
+  /// that were instantiated in this library.
+  int computeDefaultTypes(TypeBuilder dynamicType, TypeBuilder bottomType,
+      ClassBuilder objectClass);
+
+  void becomeCoreLibrary();
+
+  void addSyntheticDeclarationOfDynamic();
+
+  /// Lookups the member [name] declared in this library.
+  ///
+  /// If [required] is `true` and no member is found an internal problem is
+  /// reported.
+  Builder lookupLocalMember(String name, {bool required: false});
+
+  Builder lookup(String name, int charOffset, Uri fileUri);
+
+  /// If this is a patch library, apply its patches to [origin].
+  void applyPatches();
+
+  void recordAccess(int charOffset, int length, Uri fileUri);
+
+  void buildOutlineExpressions();
+
+  List<FieldBuilder> takeImplicitlyTypedFields();
+
+  bool get isNonNullableByDefault;
+
+  Nullability get nullable;
+
+  Nullability get nonNullable;
+
+  Nullability nullableIfTrue(bool isNullable);
+
+  NullabilityBuilder get nullableBuilder;
+
+  NullabilityBuilder get nonNullableBuilder;
+
+  NullabilityBuilder nullableBuilderIfTrue(bool isNullable);
+}
+
+abstract class LibraryBuilderImpl extends ModifierBuilderImpl
+    implements LibraryBuilder {
+  @override
+  final Scope scope;
+
+  @override
+  final Scope exportScope;
+
+  @override
+  final ScopeBuilder scopeBuilder;
+
+  @override
+  final ScopeBuilder exportScopeBuilder;
+
+  @override
+  final List<Export> exporters = <Export>[];
+
+  @override
+  LibraryBuilder partOfLibrary;
+
+  @override
   bool mayImplementRestrictedTypes = false;
 
-  LibraryBuilder(Uri fileUri, this.scope, this.exportScope)
+  LibraryBuilderImpl(Uri fileUri, this.scope, this.exportScope)
       : scopeBuilder = new ScopeBuilder(scope),
         exportScopeBuilder = new ScopeBuilder(exportScope),
         super(null, -1, fileUri);
 
+  @override
   bool get isSynthetic => false;
 
   // Deliberately unrelated return type to statically detect more accidental
   // use until Builder.target is fully retired.
+  @override
   UnrelatedTarget get target => unsupported(
       "LibraryBuilder.target is deprecated. "
       "Use LibraryBuilder.library instead.",
@@ -84,51 +245,45 @@
   ///
   /// [offset] and [length] refers to the offset and length of the source code
   /// specifying the language version.
+  @override
   void setLanguageVersion(int major, int minor,
       {int offset: 0, int length, bool explicit});
 
   @override
   Builder get parent => null;
 
+  @override
   bool get isPart => false;
 
   @override
   String get debugName => "LibraryBuilder";
 
+  @override
   Loader get loader;
 
   @override
   int get modifiers => 0;
 
-  /// Returns the [Library] built by this builder.
-  Library get library;
-
-  /// Returns the import uri for the library.
-  ///
-  /// This is the canonical uri for the library, for instance 'dart:core'.
+  @override
   Uri get uri;
 
+  @override
   Iterator<Builder> get iterator {
     return new LibraryLocalDeclarationIterator(this);
   }
 
+  @override
   NameIterator get nameIterator {
     return new LibraryLocalDeclarationNameIterator(this);
   }
 
-  Builder addBuilder(String name, Builder declaration, int charOffset);
-
+  @override
   void addExporter(
       LibraryBuilder exporter, List<Combinator> combinators, int charOffset) {
     exporters.add(new Export(exporter, this, combinators, charOffset));
   }
 
-  /// Add a problem with a severity determined by the severity of the message.
-  ///
-  /// If [fileUri] is null, it defaults to `this.fileUri`.
-  ///
-  /// See `Loader.addMessage` for an explanation of the
-  /// arguments passed to this method.
+  @override
   FormattedMessage addProblem(
       Message message, int charOffset, int length, Uri fileUri,
       {bool wasHandled: false,
@@ -144,7 +299,7 @@
         problemOnLibrary: true);
   }
 
-  /// Returns true if the export scope was modified.
+  @override
   bool addToExportScope(String name, Builder member, [int charOffset = -1]) {
     if (name.startsWith("_")) return false;
     if (member is PrefixBuilder) return false;
@@ -164,33 +319,20 @@
     return true;
   }
 
-  void addToScope(String name, Builder member, int charOffset, bool isImport);
-
-  Builder computeAmbiguousDeclaration(
-      String name, Builder declaration, Builder other, int charOffset,
-      {bool isExport: false, bool isImport: false});
-
+  @override
   int finishDeferredLoadTearoffs() => 0;
 
+  @override
   int finishForwarders() => 0;
 
+  @override
   int finishNativeMethods() => 0;
 
+  @override
   int finishPatchMethods() => 0;
 
-  /// Looks up [constructorName] in the class named [className].
-  ///
-  /// The class is looked up in this library's export scope unless
-  /// [bypassLibraryPrivacy] is true, in which case it is looked up in the
-  /// library scope of this library.
-  ///
-  /// It is an error if no such class is found, or if the class doesn't have a
-  /// matching constructor (or factory).
-  ///
-  /// If [constructorName] is null or the empty string, it's assumed to be an
-  /// unnamed constructor. it's an error if [constructorName] starts with
-  /// `"_"`, and [bypassLibraryPrivacy] is false.
-  Builder getConstructor(String className,
+  @override
+  MemberBuilder getConstructor(String className,
       {String constructorName, bool bypassLibraryPrivacy: false}) {
     constructorName ??= "";
     if (constructorName.startsWith("_") && !bypassLibraryPrivacy) {
@@ -205,7 +347,7 @@
     if (cls is ClassBuilder) {
       // TODO(ahe): This code is similar to code in `endNewExpression` in
       // `body_builder.dart`, try to share it.
-      Builder constructor =
+      MemberBuilder constructor =
           cls.findConstructorOrFactory(constructorName, -1, null, this);
       if (constructor == null) {
         // Fall-through to internal error below.
@@ -224,29 +366,23 @@
         null);
   }
 
+  @override
   int finishTypeVariables(ClassBuilder object, TypeBuilder dynamicType) => 0;
 
-  /// This method instantiates type parameters to their bounds in some cases
-  /// where they were omitted by the programmer and not provided by the type
-  /// inference.  The method returns the number of distinct type variables
-  /// that were instantiated in this library.
+  @override
   int computeDefaultTypes(TypeBuilder dynamicType, TypeBuilder bottomType,
       ClassBuilder objectClass) {
     return 0;
   }
 
+  @override
   void becomeCoreLibrary() {
     if (scope.local["dynamic"] == null) {
       addSyntheticDeclarationOfDynamic();
     }
   }
 
-  void addSyntheticDeclarationOfDynamic();
-
-  /// Lookups the member [name] declared in this library.
-  ///
-  /// If [required] is `true` and no member is found an internal problem is
-  /// reported.
+  @override
   Builder lookupLocalMember(String name, {bool required: false}) {
     Builder builder = scope.local[name];
     if (required && builder == null) {
@@ -259,35 +395,43 @@
     return builder;
   }
 
+  @override
   Builder lookup(String name, int charOffset, Uri fileUri) {
     return scope.lookup(name, charOffset, fileUri);
   }
 
-  /// If this is a patch library, apply its patches to [origin].
+  @override
   void applyPatches() {
     if (!isPatch) return;
     unsupported("${runtimeType}.applyPatches", -1, fileUri);
   }
 
+  @override
   void recordAccess(int charOffset, int length, Uri fileUri) {}
 
+  @override
   void buildOutlineExpressions() {}
 
+  @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;
   }
 
+  @override
   Nullability get nonNullable {
     return isNonNullableByDefault
         ? Nullability.nonNullable
         : Nullability.legacy;
   }
 
+  @override
   Nullability nullableIfTrue(bool isNullable) {
     if (isNonNullableByDefault) {
       return isNullable ? Nullability.nullable : Nullability.nonNullable;
@@ -295,16 +439,19 @@
     return Nullability.legacy;
   }
 
+  @override
   NullabilityBuilder get nullableBuilder {
     return isNonNullableByDefault
         ? const NullabilityBuilder.nullable()
         : const NullabilityBuilder.omitted();
   }
 
+  @override
   NullabilityBuilder get nonNullableBuilder {
     return const NullabilityBuilder.omitted();
   }
 
+  @override
   NullabilityBuilder nullableBuilderIfTrue(bool isNullable) {
     return isNullable
         ? const NullabilityBuilder.nullable()
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 ddc7a64..ce8d47f 100644
--- a/pkg/front_end/lib/src/fasta/builder/member_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/member_builder.dart
@@ -10,14 +10,46 @@
 
 import '../problems.dart' show unsupported;
 
-import 'builder.dart'
-    show ClassBuilder, Builder, LibraryBuilder, ModifierBuilder;
+import 'builder.dart' show ClassBuilder, Builder, LibraryBuilder;
 
 import 'declaration.dart';
 import 'declaration_builder.dart';
 import 'extension_builder.dart';
+import 'modifier_builder.dart';
 
-abstract class MemberBuilder extends ModifierBuilder {
+import '../kernel/class_hierarchy_builder.dart';
+
+abstract class MemberBuilder implements ModifierBuilder, ClassMember {
+  bool get isRedirectingGenerativeConstructor;
+
+  void set parent(Builder value);
+
+  LibraryBuilder get library;
+
+  /// The [Member] built by this builder;
+  Member get member;
+
+  // TODO(johnniwinther): Deprecate this.
+  Member get target;
+
+  // TODO(johnniwinther): Remove this and create a [ProcedureBuilder] interface.
+  Member get extensionTearOff;
+
+  // TODO(johnniwinther): Remove this and create a [ProcedureBuilder] interface.
+  Procedure get procedure;
+
+  // TODO(johnniwinther): Remove this and create a [ProcedureBuilder] interface.
+  ProcedureKind get kind;
+
+  void buildOutlineExpressions(LibraryBuilder library);
+
+  void inferType();
+
+  void inferCopiedType(covariant Object other);
+}
+
+abstract class MemberBuilderImpl extends ModifierBuilderImpl
+    implements MemberBuilder {
   /// For top-level members, the parent is set correctly during
   /// construction. However, for class members, the parent is initially the
   /// library and updated later.
@@ -27,8 +59,9 @@
   @override
   String get name;
 
-  MemberBuilder(this.parent, int charOffset) : super(parent, charOffset);
+  MemberBuilderImpl(this.parent, int charOffset) : super(parent, charOffset);
 
+  @override
   bool get isDeclarationInstanceMember => isDeclarationMember && !isStatic;
 
   @override
@@ -52,8 +85,10 @@
   @override
   bool get isNative => false;
 
+  @override
   bool get isRedirectingGenerativeConstructor => false;
 
+  @override
   LibraryBuilder get library {
     if (parent is LibraryBuilder) {
       LibraryBuilder library = parent;
@@ -67,30 +102,37 @@
     }
   }
 
-  /// The [Member] built by this builder;
-  Member get member;
-
   // TODO(johnniwinther): Deprecate this.
+  @override
   Member get target => member;
 
   // TODO(johnniwinther): Remove this and create a [ProcedureBuilder] interface.
+  @override
   Member get extensionTearOff =>
       unsupported("extensionTearOff", charOffset, fileUri);
 
   // TODO(johnniwinther): Remove this and create a [ProcedureBuilder] interface.
+  @override
   Procedure get procedure => unsupported("procedure", charOffset, fileUri);
 
   // TODO(johnniwinther): Remove this and create a [ProcedureBuilder] interface.
+  @override
   ProcedureKind get kind => unsupported("kind", charOffset, fileUri);
 
+  @override
   void buildOutlineExpressions(LibraryBuilder library) {}
 
   @override
   String get fullNameForErrors => name;
 
+  @override
   void inferType() => unsupported("inferType", charOffset, fileUri);
 
+  @override
   void inferCopiedType(covariant Object other) {
     unsupported("inferType", charOffset, fileUri);
   }
+
+  @override
+  ClassBuilder get classBuilder => parent is ClassBuilder ? parent : null;
 }
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 592ecf2..4912129 100644
--- a/pkg/front_end/lib/src/fasta/builder/modifier_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/modifier_builder.dart
@@ -19,32 +19,74 @@
         namedMixinApplicationMask,
         staticMask;
 
-import 'builder.dart' show Builder;
+import 'declaration.dart';
 
-abstract class ModifierBuilder extends Builder {
-  Builder parent;
-
-  final int charOffset;
-
-  final Uri fileUri;
-
-  ModifierBuilder(this.parent, this.charOffset, [Uri fileUri])
-      : fileUri = fileUri ?? parent?.fileUri;
-
+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 {
+  @override
+  Builder parent;
+
+  @override
+  final int charOffset;
+
+  @override
+  final Uri fileUri;
+
+  ModifierBuilderImpl(this.parent, this.charOffset, [Uri fileUri])
+      : 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
@@ -52,28 +94,32 @@
   // 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;
 
-  String get name;
-
+  @override
   bool get isNative => false;
 
-  String get debugName;
-
+  @override
   StringBuffer printOn(StringBuffer buffer) {
     return buffer..write(name ?? fullNameForErrors);
   }
 
+  @override
   String toString() =>
       "${isPatch ? 'patch ' : ''}$debugName(${printOn(new StringBuffer())})";
 }
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 b723bdf..3099d95 100644
--- a/pkg/front_end/lib/src/fasta/builder/nullability_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/nullability_builder.dart
@@ -61,8 +61,8 @@
       case SyntacticNullability.omitted:
         return ifOmitted;
     }
-    return unhandled("$_syntacticNullability", "buildNullability",
-        TreeNode.noOffset, noLocation);
+    return unhandled(
+        "$_syntacticNullability", "buildNullability", noLocation, null);
   }
 
   void writeNullabilityOn(StringBuffer sb) {
@@ -77,8 +77,7 @@
         // Do nothing.
         return;
     }
-    unhandled("$_syntacticNullability", "writeNullabilityOn", TreeNode.noOffset,
-        noLocation);
+    unhandled("$_syntacticNullability", "writeNullabilityOn", noLocation, null);
   }
 
   String toString() {
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 f820280..0c63ec4 100644
--- a/pkg/front_end/lib/src/fasta/builder/prefix_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/prefix_builder.dart
@@ -4,15 +4,15 @@
 
 library fasta.prefix_builder;
 
-import 'builder.dart' show Builder, LibraryBuilder, Scope;
+import 'builder.dart' show LibraryBuilder, Scope;
+
+import 'declaration.dart';
 
 import 'package:kernel/ast.dart' show LibraryDependency;
 
-import '../builder/builder.dart' show LibraryBuilder;
-
 import '../kernel/load_library_builder.dart' show LoadLibraryBuilder;
 
-class PrefixBuilder extends Builder {
+class PrefixBuilder extends BuilderImpl {
   final String name;
 
   final Scope exportScope = new Scope.top();
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 0335f23..4fd0573 100644
--- a/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/procedure_builder.dart
@@ -18,12 +18,13 @@
         Builder,
         FormalParameterBuilder,
         LibraryBuilder,
-        MemberBuilder,
         MetadataBuilder,
         Scope,
         TypeBuilder,
         TypeVariableBuilder;
 
+import 'member_builder.dart';
+
 import 'extension_builder.dart';
 import 'type_variable_builder.dart';
 
@@ -75,7 +76,7 @@
     show IncludesTypeParametersNonCovariantly, Variance;
 
 /// Common base class for constructor and procedure builders.
-abstract class FunctionBuilder extends MemberBuilder {
+abstract class FunctionBuilder extends MemberBuilderImpl {
   final List<MetadataBuilder> metadata;
 
   final int modifiers;
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 7a7bc4c..22986a9 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
@@ -40,12 +40,13 @@
         MetadataBuilder,
         NullabilityBuilder,
         TypeBuilder,
-        TypeDeclarationBuilder,
         TypeVariableBuilder;
 
 import 'declaration.dart';
 
-class TypeAliasBuilder extends TypeDeclarationBuilder {
+import 'type_declaration_builder.dart';
+
+class TypeAliasBuilder extends TypeDeclarationBuilderImpl {
   final TypeBuilder type;
 
   final List<TypeVariableBuilder> typeVariables;
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 8d4400c..a83e29d 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
@@ -11,29 +11,15 @@
         Builder,
         LibraryBuilder,
         MetadataBuilder,
-        ModifierBuilder,
         NullabilityBuilder,
         TypeBuilder;
 
-abstract class TypeDeclarationBuilder extends ModifierBuilder {
-  final List<MetadataBuilder> metadata;
+import 'modifier_builder.dart';
 
-  final int modifiers;
+abstract class TypeDeclarationBuilder implements ModifierBuilder {
+  void set parent(Builder value);
 
-  final String name;
-
-  Builder parent;
-
-  TypeDeclarationBuilder(
-      this.metadata, this.modifiers, this.name, this.parent, int charOffset,
-      [Uri fileUri])
-      : assert(modifiers != null),
-        super(parent, charOffset, fileUri);
-
-  bool get isTypeDeclaration => true;
-
-  @override
-  String get fullNameForErrors => name;
+  List<MetadataBuilder> get metadata;
 
   int get typeVariablesCount => 0;
 
@@ -44,3 +30,30 @@
   DartType buildTypesWithBuiltArguments(LibraryBuilder library,
       Nullability nullability, List<DartType> arguments);
 }
+
+abstract class TypeDeclarationBuilderImpl extends ModifierBuilderImpl
+    implements TypeDeclarationBuilder {
+  @override
+  final List<MetadataBuilder> metadata;
+
+  @override
+  final int modifiers;
+
+  @override
+  final String name;
+
+  TypeDeclarationBuilderImpl(
+      this.metadata, this.modifiers, this.name, Builder parent, int charOffset,
+      [Uri fileUri])
+      : assert(modifiers != null),
+        super(parent, charOffset, fileUri);
+
+  @override
+  bool get isTypeDeclaration => true;
+
+  @override
+  String get fullNameForErrors => name;
+
+  @override
+  int get typeVariablesCount => 0;
+}
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 87baf5b..9021954 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,12 +4,7 @@
 
 library fasta.type_variable_builder;
 
-import 'builder.dart'
-    show
-        LibraryBuilder,
-        NullabilityBuilder,
-        TypeBuilder,
-        TypeDeclarationBuilder;
+import 'builder.dart' show LibraryBuilder, NullabilityBuilder, TypeBuilder;
 
 import 'package:kernel/ast.dart'
     show DartType, Nullability, TypeParameter, TypeParameterType;
@@ -29,7 +24,9 @@
 
 import 'declaration.dart';
 
-class TypeVariableBuilder extends TypeDeclarationBuilder {
+import 'type_declaration_builder.dart';
+
+class TypeVariableBuilder extends TypeDeclarationBuilderImpl {
   TypeBuilder bound;
 
   TypeBuilder defaultType;
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 eec951a..9bd7c59 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
@@ -7,16 +7,12 @@
 import 'package:kernel/ast.dart'
     show Class, DartType, Member, Supertype, TypeParameter;
 
+import '../builder/class_builder.dart';
+
 import '../problems.dart' show unimplemented;
 
 import '../kernel/kernel_builder.dart'
-    show
-        ClassBuilder,
-        TypeBuilder,
-        LibraryBuilder,
-        MemberBuilder,
-        Scope,
-        TypeVariableBuilder;
+    show TypeBuilder, LibraryBuilder, MemberBuilder, Scope, TypeVariableBuilder;
 
 import '../modifier.dart' show abstractMask, namedMixinApplicationMask;
 
@@ -24,7 +20,7 @@
 
 import 'dill_member_builder.dart' show DillMemberBuilder;
 
-class DillClassBuilder extends ClassBuilder {
+class DillClassBuilder extends ClassBuilderImpl {
   final Class cls;
 
   DillClassBuilder(Class cls, DillLibraryBuilder parent)
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 f0b1108..ff078a1 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
@@ -16,7 +16,7 @@
 import 'dill_class_builder.dart';
 import 'dill_extension_member_builder.dart';
 
-class DillExtensionBuilder extends ExtensionBuilder {
+class DillExtensionBuilder extends ExtensionBuilderImpl {
   final Extension extension;
   List<TypeVariableBuilder> _typeParameters;
   TypeBuilder _onType;
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 e227553..6d5b52d 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
@@ -36,12 +36,14 @@
 
 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, LibraryBuilder, Scope;
+    show Builder, DynamicTypeBuilder, InvalidTypeBuilder, Scope;
 
 import '../kernel/redirecting_factory_body.dart' show RedirectingFactoryBody;
 
@@ -84,7 +86,7 @@
   }
 }
 
-class DillLibraryBuilder extends LibraryBuilder {
+class DillLibraryBuilder extends LibraryBuilderImpl {
   @override
   final Library library;
 
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 4e04550..3592e37 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,18 +7,17 @@
 import 'package:kernel/ast.dart'
     show Constructor, Field, Member, Procedure, ProcedureKind;
 
+import '../builder/member_builder.dart';
+
 import '../kernel/kernel_builder.dart'
-    show
-        Builder,
-        MemberBuilder,
-        isRedirectingGenerativeConstructorImplementation;
+    show Builder, isRedirectingGenerativeConstructorImplementation;
 
 import '../modifier.dart'
     show abstractMask, constMask, externalMask, finalMask, lateMask, staticMask;
 
 import '../problems.dart' show unhandled;
 
-class DillMemberBuilder extends MemberBuilder {
+class DillMemberBuilder extends MemberBuilderImpl {
   final int modifiers;
 
   final Member member;
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 6d6ca44..b69ed51 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -9,6 +9,8 @@
 import 'package:kernel/ast.dart';
 import 'package:kernel/type_environment.dart';
 
+import '../builder/declaration.dart';
+
 import '../builder/declaration_builder.dart';
 
 import '../builder/extension_builder.dart';
@@ -115,7 +117,7 @@
 import 'kernel_builder.dart';
 
 // TODO(ahe): Remove this and ensure all nodes have a location.
-const Null noLocation = null;
+const int noLocation = TreeNode.noOffset;
 
 // TODO(danrubel): Remove this once control flow and spread collection support
 // has been enabled by default.
@@ -407,10 +409,8 @@
   }
 
   Statement popBlock(int count, Token openBrace, Token closeBrace) {
-    return forest.createBlock(
-        openBrace,
-        const GrowableList<Statement>().pop(stack, count) ?? <Statement>[],
-        closeBrace);
+    return forest.createBlock(offsetForToken(openBrace),
+        const GrowableList<Statement>().pop(stack, count) ?? <Statement>[]);
   }
 
   Statement popStatementIfNotNull(Object value) {
@@ -795,7 +795,7 @@
             initializer ??= forest.createNullLiteral(
                 // TODO(ahe): Should store: originParameter.fileOffset
                 // https://github.com/dart-lang/sdk/issues/32289
-                null);
+                noLocation);
           }
           VariableDeclaration originParameter = builder.getFormalParameter(i);
           originParameter.initializer = initializer..parent = originParameter;
@@ -850,22 +850,17 @@
             statements.add(parameter.target);
           }
           statements.add(body);
-          body = forest.createBlock(null, statements, null)
-            ..fileOffset = charOffset;
+          body = forest.createBlock(charOffset, statements);
         }
-        body = forest.createBlock(
-            null,
-            <Statement>[
-              forest.createExpressionStatement(
-                  // This error is added after type inference is done, so we
-                  // don't need to wrap errors in SyntheticExpressionJudgment.
-                  buildProblem(fasta.messageSetterWithWrongNumberOfFormals,
-                      charOffset, noLength),
-                  null),
-              body,
-            ],
-            null)
-          ..fileOffset = charOffset;
+        body = forest.createBlock(charOffset, <Statement>[
+          forest.createExpressionStatement(
+              noLocation,
+              // This error is added after type inference is done, so we
+              // don't need to wrap errors in SyntheticExpressionJudgment.
+              buildProblem(fasta.messageSetterWithWrongNumberOfFormals,
+                  charOffset, noLength)),
+          body,
+        ]);
       }
     }
     // No-such-method forwarders get their bodies injected during outline
@@ -1051,8 +1046,7 @@
           String errorName = redirectingFactoryBody.unresolvedName;
 
           replacementNode = throwNoSuchMethodError(
-              forest.createNullLiteral(null)
-                ..fileOffset = invocation.fileOffset,
+              forest.createNullLiteral(invocation.fileOffset),
               errorName,
               forest.createArguments(
                   noLocation, invocation.arguments.positional,
@@ -1303,7 +1297,8 @@
   @override
   void handleExpressionStatement(Token token) {
     debugEvent("ExpressionStatement");
-    push(forest.createExpressionStatement(popForEffect(), token));
+    push(forest.createExpressionStatement(
+        offsetForToken(token), popForEffect()));
   }
 
   @override
@@ -1329,7 +1324,7 @@
           arguments[i] = new NamedExpression(
               "#$i",
               buildProblem(fasta.messageExpectedNamedArgument,
-                  forest.readOffset(argument), noLength))
+                  argument.fileOffset, noLength))
             ..fileOffset = beginToken.charOffset;
         }
       }
@@ -1351,8 +1346,7 @@
   @override
   void handleParenthesizedCondition(Token token) {
     debugEvent("ParenthesizedCondition");
-    push(forest.createParenthesizedCondition(
-        token, popForValue(), token.endGroup));
+    push(popForValue());
   }
 
   @override
@@ -1434,8 +1428,8 @@
       push(new VariableUseGenerator(this, token, expression.variable));
       expression.extend();
     } else {
-      VariableDeclaration variable = forest.createVariableDeclarationForValue(
-          expression.fileOffset, expression);
+      VariableDeclaration variable =
+          forest.createVariableDeclarationForValue(expression);
       push(new Cascade(variable)..fileOffset = expression.fileOffset);
       push(new VariableUseGenerator(this, token, variable));
     }
@@ -1523,15 +1517,15 @@
           // evaluating [a] and [b].
           isConstantExpression: !isSuper,
           isSuper: isSuper);
-      return negate ? forest.createNot(result, null, true) : result;
+      return negate ? forest.createNot(noLocation, result) : result;
     }
   }
 
   void doLogicalExpression(Token token) {
     Expression argument = popForValue();
     Expression receiver = pop();
-    Expression logicalExpression =
-        forest.createLogicalExpression(receiver, token, argument);
+    Expression logicalExpression = forest.createLogicalExpression(
+        offsetForToken(token), receiver, token.stringValue, argument);
     typePromoter?.exitLogicalExpression(argument, logicalExpression);
     push(logicalExpression);
   }
@@ -1831,7 +1825,7 @@
       } else if (ignoreMainInGetMainClosure &&
           name == "main" &&
           member?.name == "_getMainClosure") {
-        return forest.createNullLiteral(null)..fileOffset = charOffset;
+        return forest.createNullLiteral(charOffset);
       } else {
         return new UnresolvedNameGenerator(this, token, n);
       }
@@ -1971,7 +1965,7 @@
     if (interpolationCount == 0) {
       Token token = pop();
       String value = unescapeString(token.lexeme, token, this);
-      push(forest.createStringLiteral(value, token));
+      push(forest.createStringLiteral(offsetForToken(token), value));
     } else {
       int count = 1 + interpolationCount * 2;
       List<Object> parts = const FixedNullableList<Object>().pop(stack, count);
@@ -1988,7 +1982,8 @@
         String value =
             unescapeFirstStringPart(first.lexeme, quote, first, this);
         if (value.isNotEmpty) {
-          expressions.add(forest.createStringLiteral(value, first));
+          expressions
+              .add(forest.createStringLiteral(offsetForToken(first), value));
         }
       }
       for (int i = 1; i < parts.length - 1; i++) {
@@ -1996,7 +1991,8 @@
         if (part is Token) {
           if (part.lexeme.length != 0) {
             String value = unescape(part.lexeme, quote, part, this);
-            expressions.add(forest.createStringLiteral(value, part));
+            expressions
+                .add(forest.createStringLiteral(offsetForToken(part), value));
           }
         } else {
           expressions.add(toValue(part));
@@ -2007,10 +2003,12 @@
         String value = unescapeLastStringPart(
             last.lexeme, quote, last, last.isSynthetic, this);
         if (value.isNotEmpty) {
-          expressions.add(forest.createStringLiteral(value, last));
+          expressions
+              .add(forest.createStringLiteral(offsetForToken(last), value));
         }
       }
-      push(forest.createStringConcatenation(expressions, endToken));
+      push(forest.createStringConcatenation(
+          offsetForToken(endToken), expressions));
     }
   }
 
@@ -2018,7 +2016,7 @@
   void handleNativeClause(Token nativeToken, bool hasName) {
     debugEvent("NativeClause");
     if (hasName) {
-      forest.asLiteralString(pop());
+      pop() as StringLiteral;
     }
   }
 
@@ -2048,7 +2046,7 @@
         }
       }
     }
-    push(forest.createStringConcatenation(expressions ?? parts, null));
+    push(forest.createStringConcatenation(noLocation, expressions ?? parts));
   }
 
   @override
@@ -2058,9 +2056,9 @@
     // Postpone parsing of literals resulting in a negative value
     // (hex literals >= 2^63). These are only allowed when not negated.
     if (value == null || value < 0) {
-      push(forest.createIntLiteralLarge(token.lexeme, token));
+      push(forest.createIntLiteralLarge(offsetForToken(token), token.lexeme));
     } else {
-      push(forest.createIntLiteral(value, token));
+      push(forest.createIntLiteral(offsetForToken(token), value, token.lexeme));
     }
   }
 
@@ -2111,7 +2109,7 @@
     Expression condition = pop();
     typePromoter?.exitConditional();
     push(forest.createIfStatement(
-        ifToken, condition, thenPart, elseToken, elsePart));
+        offsetForToken(ifToken), condition, thenPart, elsePart));
   }
 
   @override
@@ -2410,31 +2408,51 @@
     List<VariableDeclaration> variables =
         buildVariableDeclarations(variableOrExpression);
     Expression condition;
-    if (forest.isExpressionStatement(conditionStatement)) {
-      condition =
-          forest.getExpressionFromExpressionStatement(conditionStatement);
+    if (conditionStatement is ExpressionStatement) {
+      condition = conditionStatement.expression;
     } else {
-      assert(forest.isEmptyStatement(conditionStatement));
+      assert(conditionStatement is EmptyStatement);
     }
     if (entry is MapEntry) {
       push(forest.createForMapEntry(
-          variables, condition, updates, entry, forToken));
+          offsetForToken(forToken), variables, condition, updates, entry));
     } else {
-      push(forest.createForElement(
-          variables, condition, updates, toValue(entry), forToken));
+      push(forest.createForElement(offsetForToken(forToken), variables,
+          condition, updates, toValue(entry)));
     }
   }
 
   @override
   void endForStatement(Token endToken) {
+    assert(checkState(endToken, <ValueKind>[
+      /* body */ ValueKind.Statement,
+      /* expression count */ ValueKind.Integer,
+      /* left separator */ ValueKind.Token,
+      /* left parenthesis */ ValueKind.Token,
+      /* for keyword */ ValueKind.Token,
+    ]));
     debugEvent("ForStatement");
     Statement body = popStatement();
 
     int updateExpressionCount = pop();
-    Token leftSeparator = pop();
-    Token leftParen = pop();
+    pop(); // Left separator.
+    pop(); // Left parenthesis.
     Token forKeyword = pop();
 
+    assert(checkState(endToken, <ValueKind>[
+      /* expressions */ ...repeatedKinds(
+          unionOfKinds(<ValueKind>[ValueKind.Expression, ValueKind.Generator]),
+          updateExpressionCount),
+      /* condition */ ValueKind.Statement,
+      /* variable or expression */ unionOfKinds(<ValueKind>[
+        ValueKind.Generator,
+        ValueKind.ExpressionOrNull,
+        ValueKind.Statement,
+        ValueKind.ObjectList,
+        ValueKind.ParserRecovery,
+      ]),
+    ]));
+
     List<Expression> updates = popListForEffect(updateExpressionCount);
     Statement conditionStatement = popStatement();
     Object variableOrExpression = pop();
@@ -2448,22 +2466,13 @@
       continueTarget.resolveContinues(forest, body);
     }
     Expression condition;
-    if (forest.isExpressionStatement(conditionStatement)) {
-      condition =
-          forest.getExpressionFromExpressionStatement(conditionStatement);
+    if (conditionStatement is ExpressionStatement) {
+      condition = conditionStatement.expression;
     } else {
-      assert(forest.isEmptyStatement(conditionStatement));
+      assert(conditionStatement is EmptyStatement);
     }
-    Statement result = forest.createForStatement(
-        forKeyword,
-        leftParen,
-        variables,
-        leftSeparator,
-        condition,
-        conditionStatement,
-        updates,
-        leftParen.endGroup,
-        body);
+    Statement result = forest.createForStatement(offsetForToken(forKeyword),
+        variables, condition, conditionStatement, updates, body);
     if (breakTarget.hasUsers) {
       result = forest.createLabeledStatement(result);
       breakTarget.resolveBreaks(forest, result);
@@ -2479,7 +2488,7 @@
   @override
   void endAwaitExpression(Token keyword, Token endToken) {
     debugEvent("AwaitExpression");
-    push(forest.createAwaitExpression(popForValue(), keyword));
+    push(forest.createAwaitExpression(offsetForToken(keyword), popForValue()));
   }
 
   @override
@@ -2538,13 +2547,13 @@
     }
 
     Expression node = forest.createListLiteral(
-        constKeyword,
-        constKeyword != null || constantContext == ConstantContext.inferred,
+        // TODO(johnniwinther): The file offset computed below will not be
+        // correct if there are type arguments but no `const` keyword.
+        offsetForToken(constKeyword ?? leftBracket),
         typeArgument,
-        typeArguments,
-        leftBracket,
         expressions,
-        rightBracket);
+        isConst: constKeyword != null ||
+            constantContext == ConstantContext.inferred);
     libraryBuilder.checkBoundsInListLiteral(node, typeEnvironment, uri);
     push(node);
   }
@@ -2575,13 +2584,13 @@
     }
 
     Expression node = forest.createSetLiteral(
-        constKeyword,
-        constKeyword != null || constantContext == ConstantContext.inferred,
+        // TODO(johnniwinther): The file offset computed below will not be
+        // correct if there are type arguments but no `const` keyword.
+        offsetForToken(constKeyword ?? leftBrace),
         typeArgument,
-        typeArguments,
-        leftBrace,
         expressions,
-        leftBrace.endGroup);
+        isConst: constKeyword != null ||
+            constantContext == ConstantContext.inferred);
     libraryBuilder.checkBoundsInSetLiteral(node, typeEnvironment, uri);
     push(node);
   }
@@ -2661,13 +2670,14 @@
     debugEvent("LiteralBool");
     bool value = optional("true", token);
     assert(value || optional("false", token));
-    push(forest.createBoolLiteral(value, token));
+    push(forest.createBoolLiteral(offsetForToken(token), value));
   }
 
   @override
   void handleLiteralDouble(Token token) {
     debugEvent("LiteralDouble");
-    push(forest.createDoubleLiteral(double.parse(token.lexeme), token));
+    push(forest.createDoubleLiteral(
+        offsetForToken(token), double.parse(token.lexeme)));
   }
 
   @override
@@ -2697,14 +2707,14 @@
     }
 
     Expression node = forest.createMapLiteral(
-        constKeyword,
-        constKeyword != null || constantContext == ConstantContext.inferred,
+        // TODO(johnniwinther): The file offset computed below will not be
+        // correct if there are type arguments but no `const` keyword.
+        offsetForToken(constKeyword ?? leftBrace),
         keyType,
         valueType,
-        typeArguments,
-        leftBrace,
         entries,
-        leftBrace.endGroup);
+        isConst: constKeyword != null ||
+            constantContext == ConstantContext.inferred);
     libraryBuilder.checkBoundsInMapLiteral(node, typeEnvironment, uri);
     push(node);
   }
@@ -2714,7 +2724,7 @@
     debugEvent("LiteralMapEntry");
     Expression value = popForValue();
     Expression key = popForValue();
-    push(forest.createMapEntry(key, colon, value));
+    push(forest.createMapEntry(offsetForToken(colon), key, value));
   }
 
   String symbolPartToString(name) {
@@ -2736,7 +2746,8 @@
         push(new ParserErrorGenerator(
             this, hashToken, fasta.messageSyntheticToken));
       } else {
-        push(forest.createSymbolLiteral(symbolPartToString(part), hashToken));
+        push(forest.createSymbolLiteral(
+            offsetForToken(hashToken), symbolPartToString(part)));
       }
     } else {
       List<Identifier> parts =
@@ -2750,7 +2761,7 @@
       for (int i = 1; i < parts.length; i++) {
         value += ".${symbolPartToString(parts[i])}";
       }
-      push(forest.createSymbolLiteral(value, hashToken));
+      push(forest.createSymbolLiteral(offsetForToken(hashToken), value));
     }
   }
 
@@ -2892,7 +2903,7 @@
         type, typeEnvironment, uri, operator.charOffset);
     Expression expression = popForValue();
     Expression asExpression =
-        forest.createAsExpression(expression, type, operator);
+        forest.createAsExpression(offsetForToken(operator), expression, type);
     push(asExpression);
   }
 
@@ -2902,8 +2913,9 @@
     DartType type = buildDartType(pop());
     Expression operand = popForValue();
     bool isInverted = not != null;
-    Expression isExpression =
-        forest.createIsExpression(operand, isOperator, not, type);
+    Expression isExpression = forest.createIsExpression(
+        offsetForToken(isOperator), operand, type,
+        notFileOffset: not != null ? offsetForToken(not) : null);
     libraryBuilder.checkBoundsInType(
         type, typeEnvironment, uri, isOperator.charOffset);
     if (operand is VariableGet) {
@@ -2937,7 +2949,7 @@
     Expression condition = pop();
     typePromoter?.exitConditional();
     push(forest.createConditionalExpression(
-        condition, question, thenExpression, colon, elseExpression));
+        offsetForToken(question), condition, thenExpression, elseExpression));
   }
 
   @override
@@ -2950,7 +2962,7 @@
           throwToken.offset,
           throwToken.length));
     } else {
-      push(forest.createThrow(throwToken, expression));
+      push(forest.createThrow(offsetForToken(throwToken), expression));
     }
   }
 
@@ -3033,7 +3045,7 @@
         variable.initializer = initializer..parent = variable;
       }
     } else if (kind != FormalParameterKind.mandatory) {
-      variable.initializer ??= forest.createNullLiteral(null)
+      variable.initializer ??= forest.createNullLiteral(noLocation)
         ..parent = variable;
     }
     if (annotations != null) {
@@ -3217,9 +3229,8 @@
       }
     }
     push(forest.createCatch(
-        onKeyword,
+        offsetForToken(onKeyword ?? catchKeyword),
         exceptionType,
-        catchKeyword,
         exception?.target,
         stackTrace?.target,
         coreTypes.stackTraceRawType(libraryBuilder.nonNullable),
@@ -3227,7 +3238,7 @@
     if (compileTimeErrors == null) {
       push(NullValue.Block);
     } else {
-      push(forest.createBlock(null, compileTimeErrors, null));
+      push(forest.createBlock(noLocation, compileTimeErrors));
     }
   }
 
@@ -3251,10 +3262,10 @@
     }
     Statement tryBlock = popStatement();
     Statement tryStatement = forest.createTryStatement(
-        tryKeyword, tryBlock, catchBlocks, finallyKeyword, finallyBlock);
+        offsetForToken(tryKeyword), tryBlock, catchBlocks, finallyBlock);
     if (compileTimeErrors != null) {
       compileTimeErrors.add(tryStatement);
-      push(forest.createBlock(null, compileTimeErrors, null));
+      push(forest.createBlock(noLocation, compileTimeErrors));
     } else {
       push(tryStatement);
     }
@@ -3288,7 +3299,7 @@
     debugEvent("UnaryPrefixExpression");
     Object receiver = pop();
     if (optional("!", token)) {
-      push(forest.createNot(toValue(receiver), token, false));
+      push(forest.createNot(offsetForToken(token), toValue(receiver)));
     } else {
       String operator = token.stringValue;
       Expression receiverValue;
@@ -3465,13 +3476,9 @@
     LocatedMessage argMessage = checkArgumentsForFunction(
         target.function, arguments, charOffset, typeParameters);
     if (argMessage != null) {
-      return throwNoSuchMethodError(
-          forest.createNullLiteral(null)..fileOffset = charOffset,
-          target.name.name,
-          arguments,
-          charOffset,
-          candidate: target,
-          message: argMessage);
+      return throwNoSuchMethodError(forest.createNullLiteral(charOffset),
+          target.name.name, arguments, charOffset,
+          candidate: target, message: argMessage);
     }
 
     bool isConst = constness == Constness.explicitConst ||
@@ -3528,13 +3535,9 @@
     LocatedMessage argMessage = checkArgumentsForFunction(
         target.function, arguments, fileOffset, typeParameters);
     if (argMessage != null) {
-      return throwNoSuchMethodError(
-          forest.createNullLiteral(null)..fileOffset = fileOffset,
-          target.name.name,
-          arguments,
-          fileOffset,
-          candidate: target,
-          message: argMessage);
+      return throwNoSuchMethodError(forest.createNullLiteral(fileOffset),
+          target.name.name, arguments, fileOffset,
+          candidate: target, message: argMessage);
     }
 
     Expression node;
@@ -3718,11 +3721,8 @@
       if (type is ProblemBuilder) {
         typeName = type.fullNameForErrors;
       }
-      push(throwNoSuchMethodError(
-          forest.createNullLiteral(null)..fileOffset = offset,
-          debugName(typeName, name),
-          arguments,
-          nameToken.charOffset));
+      push(throwNoSuchMethodError(forest.createNullLiteral(offset),
+          debugName(typeName, name), arguments, nameToken.charOffset));
     }
     constantContext = savedConstantContext;
   }
@@ -3814,11 +3814,8 @@
     }
     errorName ??= name;
 
-    return throwNoSuchMethodError(
-        forest.createNullLiteral(null)..fileOffset = charOffset,
-        errorName,
-        arguments,
-        nameLastToken.charOffset,
+    return throwNoSuchMethodError(forest.createNullLiteral(charOffset),
+        errorName, arguments, nameLastToken.charOffset,
         message: message);
   }
 
@@ -3860,10 +3857,11 @@
 
     transformCollections = true;
     if (entry is MapEntry) {
-      push(forest.createIfMapEntry(toValue(condition), entry, null, ifToken));
+      push(forest.createIfMapEntry(
+          offsetForToken(ifToken), toValue(condition), entry));
     } else {
       push(forest.createIfElement(
-          toValue(condition), toValue(entry), null, ifToken));
+          offsetForToken(ifToken), toValue(condition), toValue(entry)));
     }
   }
 
@@ -3880,13 +3878,13 @@
     if (thenEntry is MapEntry) {
       if (elseEntry is MapEntry) {
         push(forest.createIfMapEntry(
-            toValue(condition), thenEntry, elseEntry, ifToken));
+            offsetForToken(ifToken), toValue(condition), thenEntry, elseEntry));
       } else if (elseEntry is SpreadElement) {
         push(forest.createIfMapEntry(
+            offsetForToken(ifToken),
             toValue(condition),
             thenEntry,
-            new SpreadMapEntry(elseEntry.expression, elseEntry.isNullAware),
-            ifToken));
+            new SpreadMapEntry(elseEntry.expression, elseEntry.isNullAware)));
       } else {
         int offset = elseEntry is Expression
             ? elseEntry.fileOffset
@@ -3900,10 +3898,10 @@
     } else if (elseEntry is MapEntry) {
       if (thenEntry is SpreadElement) {
         push(forest.createIfMapEntry(
+            offsetForToken(ifToken),
             toValue(condition),
             new SpreadMapEntry(thenEntry.expression, thenEntry.isNullAware),
-            elseEntry,
-            ifToken));
+            elseEntry));
       } else {
         int offset = thenEntry is Expression
             ? thenEntry.fileOffset
@@ -3915,8 +3913,8 @@
           ..fileOffset = offsetForToken(ifToken));
       }
     } else {
-      push(forest.createIfElement(
-          toValue(condition), toValue(thenEntry), toValue(elseEntry), ifToken));
+      push(forest.createIfElement(offsetForToken(ifToken), toValue(condition),
+          toValue(thenEntry), toValue(elseEntry)));
     }
   }
 
@@ -3925,7 +3923,9 @@
     debugEvent("SpreadExpression");
     Object expression = pop();
     transformCollections = true;
-    push(forest.createSpreadElement(toValue(expression), spreadToken));
+    push(forest.createSpreadElement(
+        offsetForToken(spreadToken), toValue(expression),
+        isNullAware: spreadToken.lexeme == '...?'));
   }
 
   @override
@@ -4094,7 +4094,7 @@
           // This must have been a compile-time error.
           Expression error = oldInitializer;
           assert(isErroneousNode(error));
-          int offset = forest.readOffset(expression);
+          int offset = expression.fileOffset;
           push(new Let(
               new VariableDeclaration.forValue(error)..fileOffset = offset,
               expression)
@@ -4109,14 +4109,11 @@
           // This must have been a compile-time error.
           assert(isErroneousNode(variable.initializer));
 
-          push(forest.createBlock(
-              null,
-              <Statement>[
-                forest.createExpressionStatement(variable.initializer, token),
-                declaration
-              ],
-              null)
-            ..fileOffset = declaration.fileOffset);
+          push(forest.createBlock(declaration.fileOffset, <Statement>[
+            forest.createExpressionStatement(
+                offsetForToken(token), variable.initializer),
+            declaration
+          ]));
           variable.initializer = null;
         } else {
           push(declaration);
@@ -4174,8 +4171,8 @@
       body = forest.createLabeledStatement(body);
       continueTarget.resolveContinues(forest, body);
     }
-    Statement result = forest.createDoStatement(
-        doKeyword, body, whileKeyword, condition, endToken);
+    Statement result =
+        forest.createDoStatement(offsetForToken(doKeyword), body, condition);
     if (breakTarget.hasUsers) {
       result = forest.createLabeledStatement(result);
       breakTarget.resolveBreaks(forest, result);
@@ -4226,23 +4223,25 @@
     }
 
     transformCollections = true;
-    VariableDeclaration variable = buildForInVariable(lvalue);
+    VariableDeclaration variable = buildForInVariable(forToken, lvalue);
     Expression problem = checkForInVariable(lvalue, variable, forToken);
     Statement prologue = buildForInBody(lvalue, variable, forToken, inToken);
     if (entry is MapEntry) {
-      push(forest.createForInMapEntry(
-          variable, iterable, prologue, entry, problem, forToken,
+      push(forest.createForInMapEntry(offsetForToken(forToken), variable,
+          iterable, prologue, entry, problem,
           isAsync: awaitToken != null));
     } else {
-      push(forest.createForInElement(
-          variable, iterable, prologue, toValue(entry), problem, forToken,
+      push(forest.createForInElement(offsetForToken(forToken), variable,
+          iterable, prologue, toValue(entry), problem,
           isAsync: awaitToken != null));
     }
   }
 
-  VariableDeclaration buildForInVariable(Object lvalue) {
+  VariableDeclaration buildForInVariable(Token token, Object lvalue) {
     if (lvalue is VariableDeclaration) return lvalue;
-    return forest.createVariableDeclarationForValue(noLocation, null);
+    return forest.createVariableDeclaration(
+        offsetForToken(token), null, functionNestingLevel,
+        isFinal: true);
   }
 
   Expression checkForInVariable(
@@ -4284,7 +4283,7 @@
           new VariableGetImpl(variable, fact, scope)
             ..fileOffset = inKeyword.offset,
           voidContext: true);
-      return forest.createExpressionStatement(syntheticAssignment, null);
+      return forest.createExpressionStatement(noLocation, syntheticAssignment);
     }
     Message message = forest.isVariablesDeclaration(lvalue)
         ? fasta.messageForInLoopExactlyOneVariable
@@ -4293,18 +4292,18 @@
     Statement body;
     if (forest.isVariablesDeclaration(lvalue)) {
       body = forest.createBlock(
-          null,
+          noLocation,
           // New list because the declarations are not a growable list.
           new List<Statement>.from(
-              forest.variablesDeclarationExtractDeclarations(lvalue)),
-          null);
+              forest.variablesDeclarationExtractDeclarations(lvalue)));
     } else {
-      body = forest.createExpressionStatement(lvalue, null);
+      body = forest.createExpressionStatement(noLocation, lvalue);
     }
     return combineStatements(
         forest.createExpressionStatement(
-            buildProblem(message, offsetForToken(token), lengthForToken(token)),
-            null),
+            noLocation,
+            buildProblem(
+                message, offsetForToken(token), lengthForToken(token))),
         body);
   }
 
@@ -4326,7 +4325,7 @@
       body = forest.createLabeledStatement(body);
       continueTarget.resolveContinues(forest, body);
     }
-    VariableDeclaration variable = buildForInVariable(lvalue);
+    VariableDeclaration variable = buildForInVariable(forToken, lvalue);
     Expression problem = checkForInVariable(lvalue, variable, forToken);
     Statement prologue = buildForInBody(lvalue, variable, forToken, inKeyword);
     if (prologue != null) {
@@ -4353,7 +4352,7 @@
     }
     if (problem != null) {
       result = combineStatements(
-          forest.createExpressionStatement(problem, null), result);
+          forest.createExpressionStatement(noLocation, problem), result);
     }
     exitLoopOrSwitch(result);
   }
@@ -4407,7 +4406,8 @@
   void endRethrowStatement(Token rethrowToken, Token endToken) {
     debugEvent("RethrowStatement");
     if (inCatchBlock) {
-      push(forest.createRethrowStatement(rethrowToken, endToken));
+      push(forest.createRethrowStatement(
+          offsetForToken(rethrowToken), offsetForToken(endToken)));
     } else {
       push(new ExpressionStatement(buildProblem(fasta.messageRethrowNotCatch,
           offsetForToken(rethrowToken), lengthForToken(rethrowToken)))
@@ -4432,8 +4432,8 @@
       body = forest.createLabeledStatement(body);
       continueTarget.resolveContinues(forest, body);
     }
-    Statement result =
-        forest.createWhileStatement(whileKeyword, condition, body);
+    Statement result = forest.createWhileStatement(
+        offsetForToken(whileKeyword), condition, body);
     if (breakTarget.hasUsers) {
       result = forest.createLabeledStatement(result);
       breakTarget.resolveBreaks(forest, result);
@@ -4444,7 +4444,7 @@
   @override
   void handleEmptyStatement(Token token) {
     debugEvent("EmptyStatement");
-    push(forest.createEmptyStatement(token));
+    push(forest.createEmptyStatement(offsetForToken(token)));
   }
 
   @override
@@ -4462,23 +4462,62 @@
     debugEvent("Assert");
     Expression message = popForValueIfNotNull(commaToken);
     Expression condition = popForValue();
+    int fileOffset = offsetForToken(assertKeyword);
+
+    /// Return a representation of an assert that appears as a statement.
+    Statement createAssertStatement() {
+      // Compute start and end offsets for the condition expression.
+      // This code is a temporary workaround because expressions don't carry
+      // their start and end offsets currently.
+      //
+      // The token that follows leftParenthesis is considered to be the
+      // first token of the condition.
+      // TODO(ahe): this really should be condition.fileOffset.
+      int startOffset = leftParenthesis.next.offset;
+      int endOffset;
+
+      // Search forward from leftParenthesis to find the last token of
+      // the condition - which is a token immediately followed by a commaToken,
+      // right parenthesis or a trailing comma.
+      Token conditionBoundary = commaToken ?? leftParenthesis.endGroup;
+      Token conditionLastToken = leftParenthesis;
+      while (!conditionLastToken.isEof) {
+        Token nextToken = conditionLastToken.next;
+        if (nextToken == conditionBoundary) {
+          break;
+        } else if (optional(',', nextToken) &&
+            nextToken.next == conditionBoundary) {
+          // The next token is trailing comma, which means current token is
+          // the last token of the condition.
+          break;
+        }
+        conditionLastToken = nextToken;
+      }
+      if (conditionLastToken.isEof) {
+        endOffset = startOffset = -1;
+      } else {
+        endOffset = conditionLastToken.offset + conditionLastToken.length;
+      }
+
+      return forest.createAssertStatement(
+          fileOffset, condition, message, startOffset, endOffset);
+    }
 
     switch (kind) {
       case Assert.Statement:
-        push(forest.createAssertStatement(assertKeyword, leftParenthesis,
-            condition, commaToken, message, semicolonToken));
+        push(createAssertStatement());
         break;
 
       case Assert.Expression:
         // The parser has already reported an error indicating that assert
         // cannot be used in an expression.
-        push(buildProblem(fasta.messageAssertAsExpression, assertKeyword.offset,
-            assertKeyword.length));
+        push(buildProblem(
+            fasta.messageAssertAsExpression, fileOffset, assertKeyword.length));
         break;
 
       case Assert.Initializer:
         push(forest.createAssertInitializer(
-            assertKeyword, leftParenthesis, condition, commaToken, message));
+            fileOffset, createAssertStatement()));
         break;
     }
   }
@@ -4486,8 +4525,8 @@
   @override
   void endYieldStatement(Token yieldToken, Token starToken, Token endToken) {
     debugEvent("YieldStatement");
-    push(forest.createYieldStatement(
-        yieldToken, starToken, popForValue(), endToken));
+    push(forest.createYieldStatement(offsetForToken(yieldToken), popForValue(),
+        isYieldStar: starToken != null));
   }
 
   @override
@@ -4561,7 +4600,7 @@
     List<Expression> expressions = pop();
     List<int> expressionOffsets = <int>[];
     for (Expression expression in expressions) {
-      expressionOffsets.add(forest.readOffset(expression));
+      expressionOffsets.add(expression.fileOffset);
     }
     push(new SwitchCase(expressions, expressionOffsets, block,
         isDefault: defaultKeyword != null)
@@ -4666,7 +4705,7 @@
       push(buildProblemTargetOutsideLocalFunction(name, breakKeyword));
     } else {
       Statement statement =
-          forest.createBreakStatement(breakKeyword, identifier, endToken);
+          forest.createBreakStatement(offsetForToken(breakKeyword), identifier);
       target.addBreak(statement);
       push(statement);
     }
@@ -4744,8 +4783,8 @@
     } else if (target.functionNestingLevel != functionNestingLevel) {
       push(buildProblemTargetOutsideLocalFunction(name, continueKeyword));
     } else {
-      Statement statement =
-          forest.createContinueStatement(continueKeyword, identifier, endToken);
+      Statement statement = forest.createContinueStatement(
+          offsetForToken(continueKeyword), identifier);
       target.addContinue(statement);
       push(statement);
     }
@@ -4868,7 +4907,7 @@
   @override
   Expression wrapInProblem(Expression expression, Message message, int length,
       {List<LocatedMessage> context}) {
-    int charOffset = forest.readOffset(expression);
+    int charOffset = expression.fileOffset;
     Severity severity = message.code.severity;
     if (severity == Severity.error || severity == Severity.errorLegacyWarning) {
       return wrapInLocatedProblem(
@@ -4885,7 +4924,7 @@
       {List<LocatedMessage> context}) {
     // TODO(askesc): Produce explicit error expression wrapping the original.
     // See [issue 29717](https://github.com/dart-lang/sdk/issues/29717)
-    int offset = forest.readOffset(expression);
+    int offset = expression.fileOffset;
     if (offset == -1) {
       offset = message.charOffset;
     }
@@ -4909,19 +4948,17 @@
     Location location = messages.getLocationFromUri(uri, charOffset);
 
     return forest.createThrow(
-        null,
+        charOffset,
         buildStaticInvocation(
             libraryBuilder
                 .loader.coreTypes.fallThroughErrorUrlAndLineConstructor,
             forest.createArguments(noLocation, <Expression>[
-              forest.createStringLiteral("${location?.file ?? uri}", null)
-                ..fileOffset = charOffset,
-              forest.createIntLiteral(location?.line ?? 0, null)
-                ..fileOffset = charOffset,
+              forest.createStringLiteral(
+                  charOffset, "${location?.file ?? uri}"),
+              forest.createIntLiteral(charOffset, location?.line ?? 0),
             ]),
             constness: Constness.explicitNew,
-            charOffset: charOffset))
-      ..fileOffset = charOffset;
+            charOffset: charOffset));
   }
 
   Expression buildAbstractClassInstantiationError(
@@ -4933,12 +4970,11 @@
         libraryBuilder.loader.getAbstractClassInstantiationError();
     Expression invocation = buildStaticInvocation(
         constructor.target,
-        forest.createArguments(charOffset, <Expression>[
-          forest.createStringLiteral(className, null)..fileOffset = charOffset
-        ]),
+        forest.createArguments(charOffset,
+            <Expression>[forest.createStringLiteral(charOffset, className)]),
         constness: Constness.explicitNew,
         charOffset: charOffset);
-    return forest.createThrow(null, invocation)..fileOffset = charOffset;
+    return forest.createThrow(charOffset, invocation);
   }
 
   Statement buildProblemStatement(Message message, int charOffset,
@@ -5001,14 +5037,10 @@
     Builder builder = declarationBuilder.lookupLocalMember(name);
     if (builder?.next != null) {
       // Duplicated name, already reported.
-      return new LocalInitializer(
-          new VariableDeclaration.forValue(
-              buildProblem(
-                  fasta.templateDuplicatedDeclarationUse.withArguments(name),
-                  fieldNameOffset,
-                  name.length)
-                ..fileOffset = fieldNameOffset)
-            ..fileOffset = fieldNameOffset)
+      return new LocalInitializer(new VariableDeclaration.forValue(buildProblem(
+          fasta.templateDuplicatedDeclarationUse.withArguments(name),
+          fieldNameOffset,
+          name.length)))
         ..fileOffset = fieldNameOffset;
     } else if (builder is FieldBuilder && builder.isDeclarationInstanceMember) {
       initializedFields ??= <String, int>{};
@@ -5033,8 +5065,7 @@
         Expression invocation = buildStaticInvocation(
             constructor.target,
             forest.createArguments(assignmentOffset, <Expression>[
-              forest.createStringLiteral(name, null)
-                ..fileOffset = assignmentOffset
+              forest.createStringLiteral(assignmentOffset, name)
             ]),
             constness: Constness.explicitNew,
             charOffset: assignmentOffset);
@@ -5042,8 +5073,7 @@
             builder.field,
             expression,
             new VariableDeclaration.forValue(
-                forest.createThrow(null, invocation)
-                  ..fileOffset = assignmentOffset))
+                forest.createThrow(assignmentOffset, invocation)))
           ..fileOffset = assignmentOffset;
       } else {
         if (formalType != null &&
@@ -5125,15 +5155,12 @@
     if (member.isNative) {
       push(NullValue.FunctionBody);
     } else {
-      push(forest.createBlock(
-          token,
-          <Statement>[
-            buildProblemStatement(
-                fasta.templateExpectedFunctionBody.withArguments(token),
-                token.charOffset,
-                length: token.length)
-          ],
-          null));
+      push(forest.createBlock(offsetForToken(token), <Statement>[
+        buildProblemStatement(
+            fasta.templateExpectedFunctionBody.withArguments(token),
+            token.charOffset,
+            length: token.length)
+      ]));
     }
   }
 
@@ -5230,13 +5257,13 @@
       MethodInvocation node = new MethodInvocationImpl(
           receiver, callName, arguments,
           isImplicitCall: true)
-        ..fileOffset = forest.readOffset(arguments);
+        ..fileOffset = arguments.fileOffset;
       return node;
     }
 
     if (isNullAware) {
-      VariableDeclaration variable = forest.createVariableDeclarationForValue(
-          receiver.fileOffset, receiver);
+      VariableDeclaration variable =
+          forest.createVariableDeclarationForValue(receiver);
       return new NullAwareMethodInvocation(
           variable,
           forest.createMethodInvocation(offset,
@@ -5317,9 +5344,8 @@
   Expression wrapInDeferredCheck(
       Expression expression, PrefixBuilder prefix, int charOffset) {
     VariableDeclaration check = new VariableDeclaration.forValue(
-        forest.checkLibraryIsLoaded(prefix.dependency))
-      ..fileOffset = charOffset;
-    return new DeferredCheck(check, expression);
+        forest.checkLibraryIsLoaded(charOffset, prefix.dependency));
+    return new DeferredCheck(check, expression)..fileOffset = charOffset;
   }
 
   /// TODO(ahe): This method is temporarily implemented. Once type promotion is
@@ -5386,7 +5412,7 @@
   String toString() => "operator($name)";
 }
 
-class JumpTarget extends Builder {
+class JumpTarget extends BuilderImpl {
   final List<Statement> users = <Statement>[];
 
   final JumpTargetKind kind;
@@ -5456,7 +5482,7 @@
   String get fullNameForErrors => "<jump-target>";
 }
 
-class LabelTarget extends Builder implements JumpTarget {
+class LabelTarget extends BuilderImpl implements JumpTarget {
   @override
   final MemberBuilder parent;
 
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 c588cd2..dd83926 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
@@ -100,8 +100,8 @@
   void log(Object message) => print(message);
 }
 
-int compareDeclarations(Builder a, Builder b) {
-  return ClassHierarchy.compareMembers(a.target, b.target);
+int compareDeclarations(ClassMember a, ClassMember b) {
+  return ClassHierarchy.compareMembers(a.member, b.member);
 }
 
 ProcedureKind memberKind(Member member) {
@@ -112,15 +112,30 @@
   return !name.isPrivate || name.library == libraryBuilder.library;
 }
 
+abstract class ClassMember {
+  bool get isStatic;
+  bool get isField;
+  bool get isSetter;
+  bool get isGetter;
+  bool get isFinal;
+  bool get isConst;
+  Member get member;
+  bool get isDuplicate;
+  String get fullNameForErrors;
+  ClassBuilder get classBuilder;
+  Uri get fileUri;
+  int get charOffset;
+}
+
 /// Returns true if [a] is a class member conflict with [b].  [a] is assumed to
 /// be declared in the class, [b] is assumed to be inherited.
 ///
 /// See the section named "Class Member Conflicts" in [Dart Programming
 /// Language Specification](
 /// ../../../../../../docs/language/dartLangSpec.tex#classMemberConflicts).
-bool isInheritanceConflict(Builder a, Builder b) {
+bool isInheritanceConflict(ClassMember a, ClassMember b) {
   if (a.isStatic) return true;
-  if (memberKind(a.target) == memberKind(b.target)) return false;
+  if (memberKind(a.member) == memberKind(b.member)) return false;
   if (a.isField) return !(b.isField || b.isGetter || b.isSetter);
   if (b.isField) return !(a.isField || a.isGetter || a.isSetter);
   if (a.isSetter) return !(b.isGetter || b.isSetter);
@@ -129,7 +144,7 @@
   return true;
 }
 
-bool impliesSetter(Builder declaration) {
+bool impliesSetter(ClassMember declaration) {
   return declaration.isField && !(declaration.isFinal || declaration.isConst);
 }
 
@@ -337,21 +352,21 @@
   Member getInterfaceMemberKernel(Class cls, Name name, bool isSetter) {
     return getNodeFromKernelClass(cls)
         .getInterfaceMember(name, isSetter)
-        ?.target;
+        ?.member;
   }
 
   Member getDispatchTargetKernel(Class cls, Name name, bool isSetter) {
     return getNodeFromKernelClass(cls)
         .getDispatchTarget(name, isSetter)
-        ?.target;
+        ?.member;
   }
 
   Member getCombinedMemberSignatureKernel(Class cls, Name name, bool isSetter,
       int charOffset, SourceLibraryBuilder library) {
-    Builder declaration =
+    ClassMember declaration =
         getNodeFromKernelClass(cls).getInterfaceMember(name, isSetter);
     if (declaration?.isStatic ?? true) return null;
-    if (declaration.next != null) {
+    if (declaration.isDuplicate) {
       library?.addProblem(
           templateDuplicatedDeclarationUse.withArguments(name.name),
           charOffset,
@@ -362,7 +377,7 @@
     if (declaration is DelayedMember) {
       return declaration.check(this);
     } else {
-      return declaration.target;
+      return declaration.member;
     }
   }
 
@@ -391,7 +406,7 @@
 
   bool hasNoSuchMethod = false;
 
-  List<Builder> abstractMembers = null;
+  List<ClassMember> abstractMembers = null;
 
   ClassHierarchyNodeBuilder(this.hierarchy, this.classBuilder);
 
@@ -409,18 +424,19 @@
   ///
   /// If [mergeKind] is `MergeKind.supertypes`, [a] should implement [b], and
   /// [b] is implicitly abstract.
-  Builder handleMergeConflict(Builder a, Builder b, MergeKind mergeKind) {
+  ClassMember handleMergeConflict(
+      ClassMember a, ClassMember b, MergeKind mergeKind) {
     debug?.log(
         "handleMergeConflict: ${fullName(a)} ${fullName(b)} ${mergeKind}");
     // TODO(ahe): Enable this optimization, but be careful about abstract
     // methods overriding concrete methods.
     // if (cls is DillClassBuilder) return a;
     if (a == b) return a;
-    if (a.next != null || b.next != null) {
+    if (a.isDuplicate || b.isDuplicate) {
       // Don't check overrides involving duplicated members.
       return a;
     }
-    Builder result = checkInheritanceConflict(a, b);
+    ClassMember result = checkInheritanceConflict(a, b);
     if (result != null) return result;
     result = a;
     switch (mergeKind) {
@@ -452,7 +468,7 @@
             hierarchy.delayedMemberChecks.add(result);
           }
         } else if (classBuilder.isMixinApplication &&
-            a.parent != classBuilder) {
+            a.classBuilder != classBuilder) {
           result = InheritedImplementationInterfaceConflict.combined(
               classBuilder,
               a,
@@ -465,7 +481,7 @@
           }
         }
 
-        Member target = result.target;
+        Member target = result.member;
         if (target.enclosingClass != objectClass.cls &&
             target.name == noSuchMethodName) {
           hasNoSuchMethod = true;
@@ -474,7 +490,7 @@
 
       case MergeKind.membersWithSetters:
       case MergeKind.settersWithMembers:
-        if (a.parent == classBuilder && b.parent != classBuilder) {
+        if (a.classBuilder == classBuilder && b.classBuilder != classBuilder) {
           if (a is FieldBuilder) {
             if (a.isFinal && b.isSetter) {
               hierarchy.overrideChecks
@@ -512,7 +528,7 @@
         b = AbstractMemberOverridingImplementation.selectAbstract(b);
 
         // If [a] is declared in this class, it defines the interface.
-        if (a.parent == classBuilder) {
+        if (a.classBuilder == classBuilder) {
           debug?.log("supertypes: checkValidOverride("
               "${classBuilder.fullNameForErrors}, "
               "${fullName(a)}, ${fullName(b)})");
@@ -551,19 +567,19 @@
     return result;
   }
 
-  Builder checkInheritanceConflict(Builder a, Builder b) {
+  ClassMember checkInheritanceConflict(ClassMember a, ClassMember b) {
     if (a is DelayedMember) {
-      Builder result;
+      ClassMember result;
       for (int i = 0; i < a.declarations.length; i++) {
-        Builder d = checkInheritanceConflict(a.declarations[i], b);
+        ClassMember d = checkInheritanceConflict(a.declarations[i], b);
         result ??= d;
       }
       return result;
     }
     if (b is DelayedMember) {
-      Builder result;
+      ClassMember result;
       for (int i = 0; i < b.declarations.length; i++) {
-        Builder d = checkInheritanceConflict(a, b.declarations[i]);
+        ClassMember d = checkInheritanceConflict(a, b.declarations[i]);
         result ??= d;
       }
       return result;
@@ -575,12 +591,12 @@
     return null;
   }
 
-  bool inferMethodTypes(ProcedureBuilder a, Builder b) {
+  bool inferMethodTypes(ProcedureBuilder a, ClassMember b) {
     debug?.log(
         "Trying to infer types for ${fullName(a)} based on ${fullName(b)}");
     if (b is DelayedMember) {
       bool hasSameSignature = true;
-      List<Builder> declarations = b.declarations;
+      List<ClassMember> declarations = b.declarations;
       for (int i = 0; i < declarations.length; i++) {
         if (!inferMethodTypes(a, declarations[i])) {
           hasSameSignature = false;
@@ -605,7 +621,7 @@
       debug?.log("${classBuilder.fullNameForErrors} -> "
           "${aClassBuilder.fullNameForErrors} $aSubstitution");
     }
-    ClassBuilder bClassBuilder = b.parent;
+    ClassBuilder bClassBuilder = b.classBuilder;
     Substitution bSubstitution;
     if (classBuilder != bClassBuilder) {
       assert(
@@ -617,11 +633,11 @@
           "${bClassBuilder.fullNameForErrors} $bSubstitution");
     }
     Procedure aProcedure = a.procedure;
-    if (b.target is! Procedure) {
+    if (b.member is! Procedure) {
       debug?.log("Giving up 1");
       return false;
     }
-    Procedure bProcedure = b.target;
+    Procedure bProcedure = b.member;
     FunctionNode aFunction = aProcedure.function;
     FunctionNode bFunction = bProcedure.function;
 
@@ -778,10 +794,10 @@
     return result;
   }
 
-  bool inferGetterType(ProcedureBuilder a, Builder b) {
+  bool inferGetterType(ProcedureBuilder a, ClassMember b) {
     debug?.log(
         "Inferring getter types for ${fullName(a)} based on ${fullName(b)}");
-    Member bTarget = b.target;
+    Member bTarget = b.member;
     DartType bType;
     if (bTarget is Field) {
       bType = bTarget.type;
@@ -811,10 +827,10 @@
     return a.procedure.function.returnType == bType;
   }
 
-  bool inferSetterType(ProcedureBuilder a, Builder b) {
+  bool inferSetterType(ProcedureBuilder a, ClassMember b) {
     debug?.log(
         "Inferring setter types for ${fullName(a)} based on ${fullName(b)}");
-    Member bTarget = b.target;
+    Member bTarget = b.member;
     Procedure aProcedure = a.procedure;
     VariableDeclaration aParameter =
         aProcedure.function.positionalParameters.single;
@@ -851,7 +867,7 @@
     return aParameter.type == bType;
   }
 
-  void checkValidOverride(Builder a, Builder b) {
+  void checkValidOverride(ClassMember a, ClassMember b) {
     debug?.log(
         "checkValidOverride(${fullName(a)}, ${fullName(b)}) ${a.runtimeType}");
     if (a is ProcedureBuilder) {
@@ -859,8 +875,8 @@
     } else if (a.isField) {
       if (inferFieldTypes(a, b)) return;
     }
-    Member aTarget = a.target;
-    Member bTarget = b.target;
+    Member aTarget = a.member;
+    Member bTarget = b.member;
     if (aTarget is Procedure && !aTarget.isAccessor && bTarget is Procedure) {
       if (hasSameSignature(aTarget.function, bTarget.function)) return;
     }
@@ -876,12 +892,12 @@
     }
   }
 
-  bool inferFieldTypes(MemberBuilder a, Builder b) {
+  bool inferFieldTypes(MemberBuilder a, ClassMember b) {
     debug?.log("Trying to infer field types for ${fullName(a)} "
         "based on ${fullName(b)}");
     if (b is DelayedMember) {
       bool hasSameSignature = true;
-      List<Builder> declarations = b.declarations;
+      List<ClassMember> declarations = b.declarations;
       for (int i = 0; i < declarations.length; i++) {
         if (!inferFieldTypes(a, declarations[i])) {
           hasSameSignature = false;
@@ -889,7 +905,7 @@
       }
       return hasSameSignature;
     }
-    Member bTarget = b.target;
+    Member bTarget = b.member;
     DartType inheritedType;
     if (bTarget is Procedure) {
       if (bTarget.isSetter) {
@@ -924,7 +940,7 @@
       debug?.log("${classBuilder.fullNameForErrors} -> "
           "${aClassBuilder.fullNameForErrors} $aSubstitution");
     }
-    ClassBuilder bClassBuilder = b.parent;
+    ClassBuilder bClassBuilder = b.classBuilder;
     Substitution bSubstitution;
     if (classBuilder != bClassBuilder) {
       assert(
@@ -1022,10 +1038,10 @@
     }
   }
 
-  void reportInheritanceConflict(Builder a, Builder b) {
+  void reportInheritanceConflict(ClassMember a, ClassMember b) {
     String name = a.fullNameForErrors;
-    if (a.parent != b.parent) {
-      if (a.parent == classBuilder) {
+    if (a.classBuilder != b.classBuilder) {
+      if (a.classBuilder == classBuilder) {
         classBuilder.addProblem(
             messageDeclaredMemberConflictsWithInheritedMember,
             a.charOffset,
@@ -1040,8 +1056,8 @@
             context: inheritedConflictContext(a, b));
       }
     } else if (a.isStatic != b.isStatic) {
-      Builder staticMember;
-      Builder instanceMember;
+      ClassMember staticMember;
+      ClassMember instanceMember;
       if (a.isStatic) {
         staticMember = a;
         instanceMember = b;
@@ -1061,8 +1077,8 @@
       // we always report the one with higher charOffset as the duplicate,
       // the message duplication logic ensures that we only report this
       // problem once.
-      Builder existing;
-      Builder duplicate;
+      ClassMember existing;
+      ClassMember duplicate;
       assert(a.fileUri == b.fileUri);
       if (a.charOffset < b.charOffset) {
         existing = a;
@@ -1092,7 +1108,7 @@
   ///
   /// If [mergeKind] is `MergeKind.supertypes`, [member] isn't
   /// implementing/overriding anything.
-  void handleOnlyA(Builder member, MergeKind mergeKind) {
+  void handleOnlyA(ClassMember member, MergeKind mergeKind) {
     if (mergeKind == MergeKind.interfacesMembers ||
         mergeKind == MergeKind.interfacesSetters) {
       return;
@@ -1117,14 +1133,14 @@
   ///
   /// If [mergeKind] is `MergeKind.supertypes`, [member] is implicitly
   /// abstract, and not implemented.
-  Builder handleOnlyB(Builder member, MergeKind mergeKind) {
+  ClassMember handleOnlyB(ClassMember member, MergeKind mergeKind) {
     if (mergeKind == MergeKind.interfacesMembers ||
         mergeKind == MergeKind.interfacesSetters) {
       return member;
     }
     // TODO(ahe): Enable this optimization:
     // if (cls is DillClassBuilder) return member;
-    Member target = member.target;
+    Member target = member.member;
     if ((mergeKind == MergeKind.supertypesMembers ||
             mergeKind == MergeKind.supertypesSetters) ||
         ((mergeKind == MergeKind.superclassMembers ||
@@ -1148,8 +1164,8 @@
     return member;
   }
 
-  void recordAbstractMember(Builder member) {
-    abstractMembers ??= <Builder>[];
+  void recordAbstractMember(ClassMember member) {
+    abstractMembers ??= <ClassMember>[];
     if (member is DelayedMember) {
       abstractMembers.addAll(member.declarations);
     } else {
@@ -1184,33 +1200,35 @@
     }
 
     /// Members (excluding setters) declared in [cls].
-    List<Builder> localMembers = new List<Builder>.from(scope.local.values)
-      ..sort(compareDeclarations);
+    List<ClassMember> localMembers =
+        new List<ClassMember>.from(scope.local.values)
+          ..sort(compareDeclarations);
 
     /// Setters declared in [cls].
-    List<Builder> localSetters = new List<Builder>.from(scope.setters.values)
-      ..sort(compareDeclarations);
+    List<ClassMember> localSetters =
+        new List<ClassMember>.from(scope.setters.values)
+          ..sort(compareDeclarations);
 
     // Add implied setters from fields in [localMembers].
     localSetters = mergeAccessors(localMembers, localSetters);
 
     /// Members (excluding setters) declared in [cls] or its superclasses. This
     /// includes static methods of [cls], but not its superclasses.
-    List<Builder> classMembers;
+    List<ClassMember> classMembers;
 
     /// Setters declared in [cls] or its superclasses. This includes static
     /// setters of [cls], but not its superclasses.
-    List<Builder> classSetters;
+    List<ClassMember> classSetters;
 
     /// Members (excluding setters) inherited from interfaces. This contains no
     /// static members. Is null if no interfaces are implemented by this class
     /// or its superclasses.
-    List<Builder> interfaceMembers;
+    List<ClassMember> interfaceMembers;
 
     /// Setters inherited from interfaces. This contains no static setters. Is
     /// null if no interfaces are implemented by this class or its
     /// superclasses.
-    List<Builder> interfaceSetters;
+    List<ClassMember> interfaceSetters;
 
     List<TypeBuilder> superclasses;
 
@@ -1458,10 +1476,10 @@
       ClassHierarchyNode supernode, List<TypeBuilder> interfaces) {
     debug?.log("mergeInterfaces($classBuilder (${this.classBuilder}) "
         "${supernode.interfaces} ${interfaces}");
-    List<List<Builder>> memberLists =
-        new List<List<Builder>>(interfaces.length + 1);
-    List<List<Builder>> setterLists =
-        new List<List<Builder>>(interfaces.length + 1);
+    List<List<ClassMember>> memberLists =
+        new List<List<ClassMember>>(interfaces.length + 1);
+    List<List<ClassMember>> setterLists =
+        new List<List<ClassMember>>(interfaces.length + 1);
     memberLists[0] = supernode.interfaceMembers;
     setterLists[0] = supernode.interfaceSetters;
     for (int i = 0; i < interfaces.length; i++) {
@@ -1481,15 +1499,16 @@
         mergeLists(setterLists, MergeKind.interfacesSetters));
   }
 
-  List<Builder> mergeLists(List<List<Builder>> input, MergeKind mergeKind) {
+  List<ClassMember> mergeLists(
+      List<List<ClassMember>> input, MergeKind mergeKind) {
     // This is a k-way merge sort (where k is `input.length + 1`). We merge the
     // lists pairwise, which reduces the number of lists to merge by half on
     // each iteration. Consequently, we perform O(log k) merges.
     while (input.length > 1) {
-      List<List<Builder>> output = <List<Builder>>[];
+      List<List<ClassMember>> output = <List<ClassMember>>[];
       for (int i = 0; i < input.length - 1; i += 2) {
-        List<Builder> first = input[i];
-        List<Builder> second = input[i + 1];
+        List<ClassMember> first = input[i];
+        List<ClassMember> second = input[i + 1];
         if (first == null) {
           output.add(second);
         } else if (second == null) {
@@ -1509,16 +1528,17 @@
   /// Merge [and check] accessors. This entails copying mutable fields to
   /// setters to simulate implied setters, and checking that setters don't
   /// override regular methods.
-  List<Builder> mergeAccessors(List<Builder> members, List<Builder> setters) {
-    final List<Builder> mergedSetters = new List<Builder>.filled(
+  List<ClassMember> mergeAccessors(
+      List<ClassMember> members, List<ClassMember> setters) {
+    final List<ClassMember> mergedSetters = new List<ClassMember>.filled(
         members.length + setters.length, null,
         growable: true);
     int storeIndex = 0;
     int i = 0;
     int j = 0;
     while (i < members.length && j < setters.length) {
-      final Builder member = members[i];
-      final Builder setter = setters[j];
+      final ClassMember member = members[i];
+      final ClassMember setter = setters[j];
       final int compare = compareDeclarations(member, setter);
       if (compare == 0) {
         mergedSetters[storeIndex++] = setter;
@@ -1535,7 +1555,7 @@
       }
     }
     while (i < members.length) {
-      final Builder member = members[i];
+      final ClassMember member = members[i];
       if (impliesSetter(member)) {
         mergedSetters[storeIndex++] = member;
       }
@@ -1556,13 +1576,13 @@
   void reportMissingMembers() {
     Map<String, LocatedMessage> contextMap = <String, LocatedMessage>{};
     for (int i = 0; i < abstractMembers.length; i++) {
-      Builder declaration = abstractMembers[i];
-      Member target = declaration.target;
+      ClassMember declaration = abstractMembers[i];
+      Member target = declaration.member;
       if (isNameVisibleIn(target.name, classBuilder.library)) {
         String name = declaration.fullNameForErrors;
-        String parentName = declaration.parent.fullNameForErrors;
+        String className = declaration.classBuilder?.fullNameForErrors;
         String displayName =
-            declaration.isSetter ? "$parentName.$name=" : "$parentName.$name";
+            declaration.isSetter ? "$className.$name=" : "$className.$name";
         contextMap[displayName] = templateMissingImplementationCause
             .withArguments(displayName)
             .withLocation(
@@ -1587,17 +1607,17 @@
     // TODO(ahe): Implement this.
   }
 
-  List<Builder> merge(
-      List<Builder> aList, List<Builder> bList, MergeKind mergeKind) {
-    final List<Builder> result = new List<Builder>.filled(
+  List<ClassMember> merge(
+      List<ClassMember> aList, List<ClassMember> bList, MergeKind mergeKind) {
+    final List<ClassMember> result = new List<ClassMember>.filled(
         aList.length + bList.length, null,
         growable: true);
     int storeIndex = 0;
     int i = 0;
     int j = 0;
     while (i < aList.length && j < bList.length) {
-      final Builder a = aList[i];
-      final Builder b = bList[j];
+      final ClassMember a = aList[i];
+      final ClassMember b = bList[j];
       if ((mergeKind == MergeKind.interfacesMembers ||
               mergeKind == MergeKind.interfacesSetters) &&
           a.isStatic) {
@@ -1623,7 +1643,7 @@
       }
     }
     while (i < aList.length) {
-      final Builder a = aList[i];
+      final ClassMember a = aList[i];
       if (!(mergeKind == MergeKind.interfacesMembers ||
               mergeKind == MergeKind.interfacesSetters) ||
           !a.isStatic) {
@@ -1633,7 +1653,7 @@
       i++;
     }
     while (j < bList.length) {
-      final Builder b = bList[j];
+      final ClassMember b = bList[j];
       if (!b.isStatic) {
         result[storeIndex++] = handleOnlyB(b, mergeKind);
       }
@@ -1692,10 +1712,10 @@
 
   /// All the members of this class including [classMembers] of its
   /// superclasses. The members are sorted by [compareDeclarations].
-  final List<Builder> classMembers;
+  final List<ClassMember> classMembers;
 
   /// Similar to [classMembers] but for setters.
-  final List<Builder> classSetters;
+  final List<ClassMember> classSetters;
 
   /// All the interface members of this class including [interfaceMembers] of
   /// its supertypes. The members are sorted by [compareDeclarations].
@@ -1704,12 +1724,12 @@
   /// from interfaces.
   ///
   /// This may be null, in which case [classMembers] is the interface members.
-  final List<Builder> interfaceMembers;
+  final List<ClassMember> interfaceMembers;
 
   /// Similar to [interfaceMembers] but for setters.
   ///
   /// This may be null, in which case [classSetters] is the interface setters.
-  final List<Builder> interfaceSetters;
+  final List<ClassMember> interfaceSetters;
 
   /// All superclasses of [classBuilder] excluding itself. The classes are
   /// sorted by depth from the root (Object) in ascending order.
@@ -1799,21 +1819,22 @@
     return "$sb";
   }
 
-  void printMembers(List<Builder> members, StringBuffer sb, String heading) {
+  void printMembers(
+      List<ClassMember> members, StringBuffer sb, String heading) {
     sb.write("  ");
     sb.write(heading);
     sb.writeln(":");
-    for (Builder member in members) {
+    for (ClassMember member in members) {
       sb
         ..write("    ")
-        ..write(member.parent.fullNameForErrors)
+        ..write(member.classBuilder.fullNameForErrors)
         ..write(".")
         ..write(member.fullNameForErrors)
         ..writeln();
     }
   }
 
-  Builder getInterfaceMember(Name name, bool isSetter) {
+  ClassMember getInterfaceMember(Name name, bool isSetter) {
     return findMember(
         name,
         isSetter
@@ -1821,7 +1842,7 @@
             : interfaceMembers ?? classMembers);
   }
 
-  Builder findMember(Name name, List<Builder> declarations) {
+  ClassMember findMember(Name name, List<ClassMember> declarations) {
     // TODO(ahe): Consider creating a map or scope. The obvious choice would be
     // to use scopes, but they don't handle private names correctly.
 
@@ -1829,8 +1850,8 @@
     int low = 0, high = declarations.length - 1;
     while (low <= high) {
       int mid = low + ((high - low) >> 1);
-      Builder pivot = declarations[mid];
-      int comparison = ClassHierarchy.compareNames(name, pivot.target.name);
+      ClassMember pivot = declarations[mid];
+      int comparison = ClassHierarchy.compareNames(name, pivot.member.name);
       if (comparison < 0) {
         high = mid - 1;
       } else if (comparison > 0) {
@@ -1845,7 +1866,7 @@
     return null;
   }
 
-  Builder getDispatchTarget(Name name, bool isSetter) {
+  ClassMember getDispatchTarget(Name name, bool isSetter) {
     return findMember(name, isSetter ? classSetters : classMembers);
   }
 
@@ -1856,9 +1877,9 @@
 }
 
 class MergeResult {
-  final List<Builder> mergedMembers;
+  final List<ClassMember> mergedMembers;
 
-  final List<Builder> mergedSetters;
+  final List<ClassMember> mergedSetters;
 
   MergeResult(this.mergedMembers, this.mergedSetters);
 }
@@ -1889,9 +1910,9 @@
   settersWithMembers,
 }
 
-List<LocatedMessage> inheritedConflictContext(Builder a, Builder b) {
+List<LocatedMessage> inheritedConflictContext(ClassMember a, ClassMember b) {
   return inheritedConflictContextKernel(
-      a.target, b.target, a.fullNameForErrors.length);
+      a.member, b.member, a.fullNameForErrors.length);
 }
 
 List<LocatedMessage> inheritedConflictContextKernel(
@@ -2012,8 +2033,8 @@
 
 class DelayedOverrideCheck {
   final ClassBuilder classBuilder;
-  final Builder a;
-  final Builder b;
+  final ClassMember a;
+  final ClassMember b;
 
   const DelayedOverrideCheck(this.classBuilder, this.a, this.b);
 
@@ -2025,27 +2046,27 @@
           isInterfaceCheck: !classBuilder.isMixinApplication);
     }
 
-    Builder a = this.a;
+    ClassMember a = this.a;
     debug?.log("Delayed override check of ${fullName(a)} "
         "${fullName(b)} wrt. ${classBuilder.fullNameForErrors}");
-    if (classBuilder == a.parent) {
+    if (classBuilder == a.classBuilder) {
       if (a is ProcedureBuilder) {
         if (a.isGetter && !hasExplicitReturnType(a)) {
           DartType type;
           if (b.isGetter) {
-            Procedure bTarget = b.target;
+            Procedure bTarget = b.member;
             type = bTarget.function.returnType;
           } else if (b.isSetter) {
-            Procedure bTarget = b.target;
+            Procedure bTarget = b.member;
             type = bTarget.function.positionalParameters.single.type;
           } else if (b.isField) {
-            Field bTarget = b.target;
+            Field bTarget = b.member;
             type = bTarget.type;
           }
           if (type != null) {
             type = Substitution.fromInterfaceType(
                     hierarchy.getKernelTypeAsInstanceOf(
-                        classBuilder.cls.thisType, b.target.enclosingClass))
+                        classBuilder.cls.thisType, b.member.enclosingClass))
                 .substituteType(type);
             if (!a.hadTypesInferred || !b.isSetter) {
               inferReturnType(
@@ -2055,19 +2076,19 @@
         } else if (a.isSetter && !hasExplicitlyTypedFormalParameter(a, 0)) {
           DartType type;
           if (b.isGetter) {
-            Procedure bTarget = b.target;
+            Procedure bTarget = b.member;
             type = bTarget.function.returnType;
           } else if (b.isSetter) {
-            Procedure bTarget = b.target;
+            Procedure bTarget = b.member;
             type = bTarget.function.positionalParameters.single.type;
           } else if (b.isField) {
-            Field bTarget = b.target;
+            Field bTarget = b.member;
             type = bTarget.type;
           }
           if (type != null) {
             type = Substitution.fromInterfaceType(
                     hierarchy.getKernelTypeAsInstanceOf(
-                        classBuilder.cls.thisType, b.target.enclosingClass))
+                        classBuilder.cls.thisType, b.member.enclosingClass))
                 .substituteType(type);
             if (!a.hadTypesInferred || !b.isGetter) {
               inferParameterType(classBuilder, a, a.formals.single, type,
@@ -2079,19 +2100,19 @@
       } else if (a is FieldBuilder && a.type == null) {
         DartType type;
         if (b.isGetter) {
-          Procedure bTarget = b.target;
+          Procedure bTarget = b.member;
           type = bTarget.function.returnType;
         } else if (b.isSetter) {
-          Procedure bTarget = b.target;
+          Procedure bTarget = b.member;
           type = bTarget.function.positionalParameters.single.type;
         } else if (b.isField) {
-          Field bTarget = b.target;
+          Field bTarget = b.member;
           type = bTarget.type;
         }
         if (type != null) {
           type = Substitution.fromInterfaceType(
                   hierarchy.getKernelTypeAsInstanceOf(
-                      classBuilder.cls.thisType, b.target.enclosingClass))
+                      classBuilder.cls.thisType, b.member.enclosingClass))
               .substituteType(type);
           if (type != a.field.type) {
             if (a.hadTypesInferred) {
@@ -2113,26 +2134,34 @@
       }
     }
 
-    callback(a.target, b.target, a.isSetter);
+    callback(a.member, b.member, a.isSetter);
   }
 }
 
-abstract class DelayedMember extends Builder {
+abstract class DelayedMember implements ClassMember {
   /// The class which has inherited [declarations].
   @override
-  final ClassBuilder parent;
+  final ClassBuilder classBuilder;
 
   /// Conflicting declarations.
-  final List<Builder> declarations;
+  final List<ClassMember> declarations;
 
   final bool isSetter;
 
   final bool modifyKernel;
 
   DelayedMember(
-      this.parent, this.declarations, this.isSetter, this.modifyKernel);
+      this.classBuilder, this.declarations, this.isSetter, this.modifyKernel);
 
-  void addAllDeclarationsTo(List<Builder> declarations) {
+  bool get isStatic => false;
+  bool get isField => false;
+
+  bool get isGetter => false;
+  bool get isFinal => false;
+  bool get isConst => false;
+  bool get isDuplicate => false;
+
+  void addAllDeclarationsTo(List<ClassMember> declarations) {
     for (int i = 0; i < this.declarations.length; i++) {
       addDeclarationIfDifferent(this.declarations[i], declarations);
     }
@@ -2144,10 +2173,10 @@
   DelayedMember withParent(ClassBuilder parent);
 
   @override
-  Uri get fileUri => parent.fileUri;
+  Uri get fileUri => classBuilder.fileUri;
 
   @override
-  int get charOffset => parent.charOffset;
+  int get charOffset => classBuilder.charOffset;
 
   @override
   String get fullNameForErrors => declarations.map(fullName).join("%");
@@ -2155,7 +2184,7 @@
   bool get isInheritableConflict => true;
 
   @override
-  Member get target => declarations.first.target;
+  Member get member => declarations.first.member;
 }
 
 /// This represents a concrete implementation inherited from a superclass that
@@ -2168,14 +2197,14 @@
   final bool isInheritableConflict;
 
   InheritedImplementationInterfaceConflict(ClassBuilder parent,
-      List<Builder> declarations, bool isSetter, bool modifyKernel,
+      List<ClassMember> declarations, bool isSetter, bool modifyKernel,
       {this.isInheritableConflict = true})
       : super(parent, declarations, isSetter, modifyKernel);
 
   @override
   String toString() {
     return "InheritedImplementationInterfaceConflict("
-        "${parent.fullNameForErrors}, "
+        "${classBuilder.fullNameForErrors}, "
         "[${declarations.map(fullName).join(', ')}])";
   }
 
@@ -2184,31 +2213,35 @@
     if (combinedMemberSignatureResult != null) {
       return combinedMemberSignatureResult;
     }
-    if (!parent.isAbstract) {
-      Builder concreteImplementation = declarations.first;
+    if (!classBuilder.isAbstract) {
+      ClassMember concreteImplementation = declarations.first;
       for (int i = 1; i < declarations.length; i++) {
         new DelayedOverrideCheck(
-                parent, concreteImplementation, declarations[i])
+                classBuilder, concreteImplementation, declarations[i])
             .check(hierarchy);
       }
     }
-    return combinedMemberSignatureResult =
-        new InterfaceConflict(parent, declarations, isSetter, modifyKernel)
-            .check(hierarchy);
+    return combinedMemberSignatureResult = new InterfaceConflict(
+            classBuilder, declarations, isSetter, modifyKernel)
+        .check(hierarchy);
   }
 
   @override
   DelayedMember withParent(ClassBuilder parent) {
-    return parent == this.parent
+    return parent == this.classBuilder
         ? this
         : new InheritedImplementationInterfaceConflict(
             parent, declarations, isSetter, modifyKernel);
   }
 
-  static Builder combined(ClassBuilder parent, Builder concreteImplementation,
-      Builder other, bool isSetter, bool createForwarders,
+  static ClassMember combined(
+      ClassBuilder parent,
+      ClassMember concreteImplementation,
+      ClassMember other,
+      bool isSetter,
+      bool createForwarders,
       {bool isInheritableConflict = true}) {
-    List<Builder> declarations = <Builder>[];
+    List<ClassMember> declarations = <ClassMember>[];
     if (concreteImplementation is DelayedMember) {
       concreteImplementation.addAllDeclarationsTo(declarations);
     } else {
@@ -2230,7 +2263,7 @@
 }
 
 class InterfaceConflict extends DelayedMember {
-  InterfaceConflict(ClassBuilder parent, List<Builder> declarations,
+  InterfaceConflict(ClassBuilder parent, List<ClassMember> declarations,
       bool isSetter, bool modifyKernel)
       : super(parent, declarations, isSetter, modifyKernel);
 
@@ -2238,7 +2271,7 @@
 
   @override
   String toString() {
-    return "InterfaceConflict(${parent.fullNameForErrors}, "
+    return "InterfaceConflict(${classBuilder.fullNameForErrors}, "
         "[${declarations.map(fullName).join(', ')}])";
   }
 
@@ -2256,8 +2289,8 @@
     } else if (member is Field) {
       type = member.type;
     } else {
-      unhandled("${member.runtimeType}", "$member", parent.charOffset,
-          parent.fileUri);
+      unhandled("${member.runtimeType}", "$member", classBuilder.charOffset,
+          classBuilder.fileUri);
     }
     return Substitution.fromInterfaceType(hierarchy.getKernelTypeAsInstanceOf(
             thisType, member.enclosingClass))
@@ -2279,15 +2312,15 @@
     if (combinedMemberSignatureResult != null) {
       return combinedMemberSignatureResult;
     }
-    if (parent.library is! SourceLibraryBuilder) {
-      return combinedMemberSignatureResult = declarations.first.target;
+    if (classBuilder.library is! SourceLibraryBuilder) {
+      return combinedMemberSignatureResult = declarations.first.member;
     }
-    DartType thisType = parent.cls.thisType;
-    Builder bestSoFar;
+    DartType thisType = classBuilder.cls.thisType;
+    ClassMember bestSoFar;
     DartType bestTypeSoFar;
     for (int i = declarations.length - 1; i >= 0; i--) {
-      Builder candidate = declarations[i];
-      Member target = candidate.target;
+      ClassMember candidate = declarations[i];
+      Member target = candidate.member;
       DartType candidateType = computeMemberType(hierarchy, thisType, target);
       if (bestSoFar == null) {
         bestSoFar = candidate;
@@ -2307,18 +2340,18 @@
     if (bestSoFar != null) {
       debug?.log("Combined Member Signature bestSoFar: ${fullName(bestSoFar)}");
       for (int i = 0; i < declarations.length; i++) {
-        Builder candidate = declarations[i];
-        Member target = candidate.target;
+        ClassMember candidate = declarations[i];
+        Member target = candidate.member;
         DartType candidateType = computeMemberType(hierarchy, thisType, target);
         if (!isMoreSpecific(hierarchy, bestTypeSoFar, candidateType)) {
           debug?.log("Combined Member Signature: "
               "${fullName(bestSoFar)} !<: ${fullName(candidate)}");
 
-          String uri = '${parent.library.uri}';
+          String uri = '${classBuilder.library.uri}';
           if (uri == 'dart:js' &&
-                  parent.fileUri.pathSegments.last == 'js_dart2js.dart' ||
+                  classBuilder.fileUri.pathSegments.last == 'js_dart2js.dart' ||
               uri == 'dart:_interceptors' &&
-                  parent.fileUri.pathSegments.last == 'js_number.dart') {
+                  classBuilder.fileUri.pathSegments.last == 'js_number.dart') {
             // TODO(johnniwinther): Fix the dart2js libraries and remove the
             // above URIs.
           } else {
@@ -2330,17 +2363,18 @@
       }
     }
     if (bestSoFar == null) {
-      String name = parent.fullNameForErrors;
-      int length = parent.isAnonymousMixinApplication ? 1 : name.length;
-      List<LocatedMessage> context = declarations.map((Builder d) {
+      String name = classBuilder.fullNameForErrors;
+      int length = classBuilder.isAnonymousMixinApplication ? 1 : name.length;
+      List<LocatedMessage> context = declarations.map((ClassMember d) {
         return messageDeclaredMemberConflictsWithInheritedMemberCause
             .withLocation(d.fileUri, d.charOffset, d.fullNameForErrors.length);
       }).toList();
 
-      parent.addProblem(
+      classBuilder.addProblem(
           templateCombinedMemberSignatureFailed.withArguments(
-              parent.fullNameForErrors, declarations.first.fullNameForErrors),
-          parent.charOffset,
+              classBuilder.fullNameForErrors,
+              declarations.first.fullNameForErrors),
+          classBuilder.charOffset,
           length,
           context: context);
       return null;
@@ -2349,29 +2383,30 @@
         "${fullName(bestSoFar)}");
 
     ProcedureKind kind = ProcedureKind.Method;
+    Member bestMemberSoFar = bestSoFar.member;
     if (bestSoFar.isField || bestSoFar.isSetter || bestSoFar.isGetter) {
       kind = isSetter ? ProcedureKind.Setter : ProcedureKind.Getter;
-    } else if (bestSoFar.target is Procedure &&
-        bestSoFar.target.kind == ProcedureKind.Operator) {
+    } else if (bestMemberSoFar is Procedure &&
+        bestMemberSoFar.kind == ProcedureKind.Operator) {
       kind = ProcedureKind.Operator;
     }
 
     if (modifyKernel) {
-      debug?.log("Combined Member Signature of ${fullNameForErrors}: "
-          "new ForwardingNode($parent, $bestSoFar, $declarations, $kind)");
-      Member stub =
-          new ForwardingNode(hierarchy, parent, bestSoFar, declarations, kind)
-              .finalize();
-      if (parent.cls == stub.enclosingClass) {
-        parent.cls.addMember(stub);
-        SourceLibraryBuilder library = parent.library;
-        if (bestSoFar.target is Procedure) {
-          library.forwardersOrigins..add(stub)..add(bestSoFar.target);
+      debug?.log("Combined Member Signature of ${fullNameForErrors}: new "
+          "ForwardingNode($classBuilder, $bestSoFar, $declarations, $kind)");
+      Member stub = new ForwardingNode(
+              hierarchy, classBuilder, bestSoFar, declarations, kind)
+          .finalize();
+      if (classBuilder.cls == stub.enclosingClass) {
+        classBuilder.cls.addMember(stub);
+        SourceLibraryBuilder library = classBuilder.library;
+        if (bestSoFar.member is Procedure) {
+          library.forwardersOrigins..add(stub)..add(bestSoFar.member);
         }
         debug?.log("Combined Member Signature of ${fullNameForErrors}: "
             "added stub $stub");
-        if (parent.isMixinApplication) {
-          return combinedMemberSignatureResult = bestSoFar.target;
+        if (classBuilder.isMixinApplication) {
+          return combinedMemberSignatureResult = bestSoFar.member;
         } else {
           return combinedMemberSignatureResult = stub;
         }
@@ -2380,19 +2415,19 @@
 
     debug?.log(
         "Combined Member Signature of ${fullNameForErrors}: picked bestSoFar");
-    return combinedMemberSignatureResult = bestSoFar.target;
+    return combinedMemberSignatureResult = bestSoFar.member;
   }
 
   @override
   DelayedMember withParent(ClassBuilder parent) {
-    return parent == this.parent
+    return parent == this.classBuilder
         ? this
         : new InterfaceConflict(parent, declarations, isSetter, modifyKernel);
   }
 
-  static Builder combined(ClassBuilder parent, Builder a, Builder b,
+  static ClassMember combined(ClassBuilder parent, ClassMember a, ClassMember b,
       bool isSetter, bool createForwarders) {
-    List<Builder> declarations = <Builder>[];
+    List<ClassMember> declarations = <ClassMember>[];
     if (a is DelayedMember) {
       a.addAllDeclarationsTo(declarations);
     } else {
@@ -2415,20 +2450,22 @@
 class AbstractMemberOverridingImplementation extends DelayedMember {
   AbstractMemberOverridingImplementation(
       ClassBuilder parent,
-      Builder abstractMember,
-      Builder concreteImplementation,
+      ClassMember abstractMember,
+      ClassMember concreteImplementation,
       bool isSetter,
       bool modifyKernel)
-      : super(parent, <Builder>[concreteImplementation, abstractMember],
+      : super(parent, <ClassMember>[concreteImplementation, abstractMember],
             isSetter, modifyKernel);
 
-  Builder get concreteImplementation => declarations[0];
+  ClassMember get concreteImplementation => declarations[0];
 
-  Builder get abstractMember => declarations[1];
+  ClassMember get abstractMember => declarations[1];
 
   Member check(ClassHierarchyBuilder hierarchy) {
-    if (!parent.isAbstract && !hierarchy.nodes[parent.cls].hasNoSuchMethod) {
-      new DelayedOverrideCheck(parent, concreteImplementation, abstractMember)
+    if (!classBuilder.isAbstract &&
+        !hierarchy.nodes[classBuilder.cls].hasNoSuchMethod) {
+      new DelayedOverrideCheck(
+              classBuilder, concreteImplementation, abstractMember)
           .check(hierarchy);
     }
 
@@ -2439,21 +2476,22 @@
     if (modifyKernel) {
       // This call will add a body to the abstract method if needed for
       // isGenericCovariantImpl checks.
-      new ForwardingNode(hierarchy, parent, abstractMember, declarations, kind)
+      new ForwardingNode(
+              hierarchy, classBuilder, abstractMember, declarations, kind)
           .finalize();
     }
-    return abstractMember.target;
+    return abstractMember.member;
   }
 
   @override
   DelayedMember withParent(ClassBuilder parent) {
-    return parent == this.parent
+    return parent == this.classBuilder
         ? this
         : new AbstractMemberOverridingImplementation(parent, abstractMember,
             concreteImplementation, isSetter, modifyKernel);
   }
 
-  static Builder selectAbstract(Builder declaration) {
+  static ClassMember selectAbstract(ClassMember declaration) {
     if (declaration is AbstractMemberOverridingImplementation) {
       return declaration.abstractMember;
     } else {
@@ -2461,7 +2499,7 @@
     }
   }
 
-  static Builder selectConcrete(Builder declaration) {
+  static ClassMember selectConcrete(ClassMember declaration) {
     if (declaration is AbstractMemberOverridingImplementation) {
       return declaration.concreteImplementation;
     } else {
@@ -2471,12 +2509,12 @@
 }
 
 void addDeclarationIfDifferent(
-    Builder declaration, List<Builder> declarations) {
-  Member target = declaration.target;
+    ClassMember declaration, List<ClassMember> declarations) {
+  Member target = declaration.member;
   if (target is Procedure) {
     FunctionNode function = target.function;
     for (int i = 0; i < declarations.length; i++) {
-      Member other = declarations[i].target;
+      Member other = declarations[i].member;
       if (other is Procedure) {
         if (hasSameSignature(function, other.function)) return;
       }
@@ -2489,42 +2527,43 @@
   declarations.add(declaration);
 }
 
-String fullName(Builder declaration) {
+String fullName(ClassMember declaration) {
   String suffix = declaration.isSetter ? "=" : "";
   if (declaration is DelayedMember) {
     return "${declaration.fullNameForErrors}$suffix";
   }
-  Builder parent = declaration.parent;
-  return parent == null
+  String className = declaration.classBuilder?.fullNameForErrors;
+  return className == null
       ? "${declaration.fullNameForErrors}$suffix"
-      : "${parent.fullNameForErrors}.${declaration.fullNameForErrors}$suffix";
+      : "${className}.${declaration.fullNameForErrors}$suffix";
 }
 
 int compareNamedParameters(VariableDeclaration a, VariableDeclaration b) {
   return a.name.compareTo(b.name);
 }
 
-bool isAbstract(Builder declaration) {
-  return declaration.target.isAbstract || declaration is InterfaceConflict;
+bool isAbstract(ClassMember declaration) {
+  return declaration.member.isAbstract || declaration is InterfaceConflict;
 }
 
 bool inferParameterType(
-    ClassBuilder cls,
-    ProcedureBuilder member,
-    FormalParameterBuilder parameter,
+    ClassBuilder classBuilder,
+    ProcedureBuilder memberBuilder,
+    FormalParameterBuilder parameterBuilder,
     DartType type,
     bool hadTypesInferred,
     ClassHierarchyBuilder hierarchy) {
-  debug?.log("Inferred type ${type} for ${parameter}");
-  if (type == parameter.target.type) return true;
+  debug?.log("Inferred type ${type} for ${parameterBuilder}");
+  if (type == parameterBuilder.variable.type) return true;
   bool result = true;
   if (hadTypesInferred) {
-    reportCantInferParameterType(cls, member, parameter, hierarchy);
+    reportCantInferParameterType(
+        classBuilder, memberBuilder, parameterBuilder, hierarchy);
     type = const InvalidType();
     result = false;
   }
-  parameter.target.type = type;
-  member.hadTypesInferred = true;
+  parameterBuilder.variable.type = type;
+  memberBuilder.hadTypesInferred = true;
   return result;
 }
 
@@ -2626,7 +2665,7 @@
   return declaration is ClassBuilder ? declaration : null;
 }
 
-bool hasExplicitReturnType(Builder declaration) {
+bool hasExplicitReturnType(ClassMember declaration) {
   assert(declaration is ProcedureBuilder || declaration is DillMemberBuilder,
       "${declaration.runtimeType}");
   return declaration is ProcedureBuilder
@@ -2634,7 +2673,7 @@
       : true;
 }
 
-bool hasExplicitlyTypedFormalParameter(Builder declaration, int index) {
+bool hasExplicitlyTypedFormalParameter(ClassMember declaration, int index) {
   assert(declaration is ProcedureBuilder || declaration is DillMemberBuilder,
       "${declaration.runtimeType}");
   return declaration is ProcedureBuilder
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 2a22a37..1251c2e 100644
--- a/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/expression_generator.dart
@@ -159,7 +159,7 @@
       bool voidContext: false,
       Procedure interfaceTarget}) {
     return buildCompoundAssignment(
-        binaryOperator, _forest.createIntLiteral(1, null)..fileOffset = offset,
+        binaryOperator, _forest.createIntLiteral(offset, 1),
         offset: offset,
         // TODO(johnniwinther): We are missing some void contexts here. For
         // instance `++a?.b;` is not providing a void context making it default
@@ -386,7 +386,7 @@
       {int offset = TreeNode.noOffset,
       bool voidContext = false,
       Procedure interfaceTarget}) {
-    Expression value = _forest.createIntLiteral(1, null)..fileOffset = offset;
+    Expression value = _forest.createIntLiteral(offset, 1);
     if (voidContext) {
       return buildCompoundAssignment(binaryOperator, value,
           offset: offset,
@@ -394,8 +394,8 @@
           interfaceTarget: interfaceTarget,
           isPostIncDec: true);
     }
-    VariableDeclaration read = _helper.forest
-        .createVariableDeclarationForValue(fileOffset, _createRead());
+    VariableDeclaration read =
+        _helper.forest.createVariableDeclarationForValue(_createRead());
     MethodInvocation binary = _helper.forest.createMethodInvocation(
         offset,
         _helper.createVariableGet(read, fileOffset),
@@ -403,8 +403,7 @@
         _helper.forest.createArguments(offset, <Expression>[value]),
         interfaceTarget: interfaceTarget);
     VariableDeclaration write = _helper.forest
-        .createVariableDeclarationForValue(
-            offset, _createWrite(offset, binary));
+        .createVariableDeclarationForValue(_createWrite(offset, binary));
     return new LocalPostIncDec(read, write)..fileOffset = offset;
   }
 
@@ -502,8 +501,8 @@
   @override
   Expression buildIfNullAssignment(Expression value, DartType type, int offset,
       {bool voidContext = false}) {
-    VariableDeclaration variable = _helper.forest
-        .createVariableDeclarationForValue(receiver.fileOffset, receiver);
+    VariableDeclaration variable =
+        _helper.forest.createVariableDeclarationForValue(receiver);
     PropertyGet read = new PropertyGet(
         _helper.createVariableGet(variable, receiver.fileOffset), name)
       ..fileOffset = fileOffset;
@@ -521,8 +520,8 @@
       Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
-    VariableDeclaration variable = _helper.forest
-        .createVariableDeclarationForValue(receiver.fileOffset, receiver);
+    VariableDeclaration variable =
+        _helper.forest.createVariableDeclarationForValue(receiver);
     MethodInvocation binary = _helper.forest.createMethodInvocation(
         offset,
         new PropertyGet(
@@ -542,7 +541,7 @@
       {int offset = TreeNode.noOffset,
       bool voidContext = false,
       Procedure interfaceTarget}) {
-    Expression value = _forest.createIntLiteral(1, null)..fileOffset = offset;
+    Expression value = _forest.createIntLiteral(offset, 1);
     if (voidContext) {
       return buildCompoundAssignment(binaryOperator, value,
           offset: offset,
@@ -550,10 +549,9 @@
           interfaceTarget: interfaceTarget,
           isPostIncDec: true);
     }
-    VariableDeclaration variable = _helper.forest
-        .createVariableDeclarationForValue(receiver.fileOffset, receiver);
+    VariableDeclaration variable =
+        _helper.forest.createVariableDeclarationForValue(receiver);
     VariableDeclaration read = _helper.forest.createVariableDeclarationForValue(
-        fileOffset,
         new PropertyGet(
             _helper.createVariableGet(variable, receiver.fileOffset), name)
           ..fileOffset = fileOffset);
@@ -564,14 +562,12 @@
         _helper.forest.createArguments(offset, <Expression>[value]),
         interfaceTarget: interfaceTarget);
     VariableDeclaration write = _helper.forest
-        .createVariableDeclarationForValue(
-            offset,
-            _helper.forest.createPropertySet(
-                fileOffset,
-                _helper.createVariableGet(variable, receiver.fileOffset),
-                name,
-                binary,
-                forEffect: true));
+        .createVariableDeclarationForValue(_helper.forest.createPropertySet(
+            fileOffset,
+            _helper.createVariableGet(variable, receiver.fileOffset),
+            name,
+            binary,
+            forEffect: true));
     return new PropertyPostIncDec(variable, read, write)..fileOffset = offset;
   }
 
@@ -716,7 +712,7 @@
       {int offset = TreeNode.noOffset,
       bool voidContext = false,
       Procedure interfaceTarget}) {
-    Expression value = _forest.createIntLiteral(1, null)..fileOffset = offset;
+    Expression value = _forest.createIntLiteral(offset, 1);
     if (voidContext) {
       return buildCompoundAssignment(binaryOperator, value,
           offset: offset,
@@ -725,7 +721,6 @@
           isPostIncDec: true);
     }
     VariableDeclaration read = _helper.forest.createVariableDeclarationForValue(
-        fileOffset,
         new PropertyGet(_forest.createThisExpression(fileOffset), name)
           ..fileOffset = fileOffset);
     MethodInvocation binary = _helper.forest.createMethodInvocation(
@@ -736,7 +731,7 @@
         interfaceTarget: interfaceTarget);
     VariableDeclaration write = _helper.forest
         .createVariableDeclarationForValue(
-            offset, _createWrite(fileOffset, binary, forEffect: true));
+            _createWrite(fileOffset, binary, forEffect: true));
     return new PropertyPostIncDec.onReadOnly(read, write)..fileOffset = offset;
   }
 
@@ -805,9 +800,8 @@
 
   @override
   Expression buildSimpleRead() {
-    VariableDeclaration variable = _helper.forest
-        .createVariableDeclarationForValue(
-            receiverExpression.fileOffset, receiverExpression);
+    VariableDeclaration variable =
+        _helper.forest.createVariableDeclarationForValue(receiverExpression);
     PropertyGet read = new PropertyGet(
         _helper.createVariableGet(variable, receiverExpression.fileOffset),
         name)
@@ -818,9 +812,8 @@
 
   @override
   Expression buildAssignment(Expression value, {bool voidContext = false}) {
-    VariableDeclaration variable = _helper.forest
-        .createVariableDeclarationForValue(
-            receiverExpression.fileOffset, receiverExpression);
+    VariableDeclaration variable =
+        _helper.forest.createVariableDeclarationForValue(receiverExpression);
     PropertySet read = _helper.forest.createPropertySet(
         fileOffset,
         _helper.createVariableGet(variable, receiverExpression.fileOffset),
@@ -862,7 +855,7 @@
       bool voidContext: false,
       Procedure interfaceTarget}) {
     return buildCompoundAssignment(
-        binaryOperator, _forest.createIntLiteral(1, null)..fileOffset = offset,
+        binaryOperator, _forest.createIntLiteral(offset, 1),
         offset: offset,
         voidContext: voidContext,
         interfaceTarget: interfaceTarget,
@@ -962,7 +955,7 @@
       {int offset = TreeNode.noOffset,
       bool voidContext = false,
       Procedure interfaceTarget}) {
-    Expression value = _forest.createIntLiteral(1, null)..fileOffset = offset;
+    Expression value = _forest.createIntLiteral(offset, 1);
     if (voidContext) {
       return buildCompoundAssignment(binaryOperator, value,
           offset: offset,
@@ -970,8 +963,8 @@
           interfaceTarget: interfaceTarget,
           isPostIncDec: true);
     }
-    VariableDeclaration read = _helper.forest
-        .createVariableDeclarationForValue(fileOffset, _createRead());
+    VariableDeclaration read =
+        _helper.forest.createVariableDeclarationForValue(_createRead());
     MethodInvocation binary = _helper.forest.createMethodInvocation(
         offset,
         _helper.createVariableGet(read, fileOffset),
@@ -979,8 +972,7 @@
         _helper.forest.createArguments(offset, <Expression>[value]),
         interfaceTarget: interfaceTarget);
     VariableDeclaration write = _helper.forest
-        .createVariableDeclarationForValue(
-            offset, _createWrite(fileOffset, binary));
+        .createVariableDeclarationForValue(_createWrite(fileOffset, binary));
     return new StaticPostIncDec(read, write)..fileOffset = offset;
   }
 
@@ -1104,7 +1096,7 @@
       {int offset = TreeNode.noOffset,
       bool voidContext = false,
       Procedure interfaceTarget}) {
-    Expression value = _forest.createIntLiteral(1, null)..fileOffset = offset;
+    Expression value = _forest.createIntLiteral(offset, 1);
     return buildCompoundAssignment(binaryOperator, value,
         offset: offset,
         voidContext: voidContext,
@@ -1115,7 +1107,7 @@
   @override
   Expression doInvocation(int offset, Arguments arguments) {
     return _helper.buildMethodInvocation(
-        buildSimpleRead(), callName, arguments, _forest.readOffset(arguments),
+        buildSimpleRead(), callName, arguments, arguments.fileOffset,
         isImplicitCall: true);
   }
 
@@ -1235,7 +1227,7 @@
       {int offset = TreeNode.noOffset,
       bool voidContext = false,
       Procedure interfaceTarget}) {
-    Expression value = _forest.createIntLiteral(1, null)..fileOffset = offset;
+    Expression value = _forest.createIntLiteral(offset, 1);
     return buildCompoundAssignment(binaryOperator, value,
         offset: offset,
         voidContext: voidContext,
@@ -1343,7 +1335,7 @@
       {int offset = TreeNode.noOffset,
       bool voidContext = false,
       Procedure interfaceTarget}) {
-    Expression value = _forest.createIntLiteral(1, null)..fileOffset = offset;
+    Expression value = _forest.createIntLiteral(offset, 1);
     return buildCompoundAssignment(binaryOperator, value,
         offset: offset,
         voidContext: voidContext,
@@ -1527,7 +1519,7 @@
       {int offset = TreeNode.noOffset,
       bool voidContext = false,
       Procedure interfaceTarget}) {
-    Expression value = _forest.createIntLiteral(1, null)..fileOffset = offset;
+    Expression value = _forest.createIntLiteral(offset, 1);
     if (voidContext) {
       return buildCompoundAssignment(binaryOperator, value,
           offset: offset,
@@ -1535,8 +1527,8 @@
           interfaceTarget: interfaceTarget,
           isPostIncDec: true);
     }
-    VariableDeclaration read = _helper.forest
-        .createVariableDeclarationForValue(fileOffset, _createRead());
+    VariableDeclaration read =
+        _helper.forest.createVariableDeclarationForValue(_createRead());
     MethodInvocation binary = _helper.forest.createMethodInvocation(
         offset,
         _helper.createVariableGet(read, fileOffset),
@@ -1544,8 +1536,7 @@
         _helper.forest.createArguments(offset, <Expression>[value]),
         interfaceTarget: interfaceTarget);
     VariableDeclaration write = _helper.forest
-        .createVariableDeclarationForValue(
-            offset, _createWrite(offset, binary));
+        .createVariableDeclarationForValue(_createWrite(offset, binary));
     return new StaticPostIncDec(read, write)..fileOffset = offset;
   }
 
@@ -1805,7 +1796,7 @@
       {int offset = TreeNode.noOffset,
       bool voidContext = false,
       Procedure interfaceTarget}) {
-    Expression value = _forest.createIntLiteral(1, null)..fileOffset = offset;
+    Expression value = _forest.createIntLiteral(offset, 1);
     if (voidContext) {
       return buildCompoundAssignment(binaryOperator, value,
           offset: offset,
@@ -1813,8 +1804,8 @@
           interfaceTarget: interfaceTarget,
           isPostIncDec: true);
     }
-    VariableDeclaration read = _helper.forest
-        .createVariableDeclarationForValue(fileOffset, _createRead());
+    VariableDeclaration read =
+        _helper.forest.createVariableDeclarationForValue(_createRead());
     MethodInvocation binary = _helper.forest.createMethodInvocation(
         offset,
         _helper.createVariableGet(read, fileOffset),
@@ -1823,7 +1814,7 @@
         interfaceTarget: interfaceTarget);
     VariableDeclaration write = _helper.forest
         .createVariableDeclarationForValue(
-            offset, _createWrite(fileOffset, binary, forEffect: true));
+            _createWrite(fileOffset, binary, forEffect: true));
     return new PropertyPostIncDec.onReadOnly(read, write)..fileOffset = offset;
   }
 
@@ -2041,8 +2032,8 @@
   @override
   Expression buildSimpleRead() {
     if (isNullAware) {
-      VariableDeclaration variable = _helper.forest
-          .createVariableDeclarationForValue(receiver.fileOffset, receiver);
+      VariableDeclaration variable =
+          _helper.forest.createVariableDeclarationForValue(receiver);
       return new NullAwareExtension(variable,
           _createRead(_helper.createVariableGet(variable, variable.fileOffset)))
         ..fileOffset = fileOffset;
@@ -2070,8 +2061,8 @@
   @override
   Expression buildAssignment(Expression value, {bool voidContext: false}) {
     if (isNullAware) {
-      VariableDeclaration variable = _helper.forest
-          .createVariableDeclarationForValue(receiver.fileOffset, receiver);
+      VariableDeclaration variable =
+          _helper.forest.createVariableDeclarationForValue(receiver);
       return new NullAwareExtension(
           variable,
           _createWrite(fileOffset,
@@ -2102,8 +2093,8 @@
   Expression buildIfNullAssignment(Expression value, DartType type, int offset,
       {bool voidContext: false}) {
     if (isNullAware) {
-      VariableDeclaration variable = _helper.forest
-          .createVariableDeclarationForValue(receiver.fileOffset, receiver);
+      VariableDeclaration variable =
+          _helper.forest.createVariableDeclarationForValue(receiver);
       Expression read =
           _createRead(_helper.createVariableGet(variable, receiver.fileOffset));
       Expression write = _createWrite(fileOffset,
@@ -2115,8 +2106,8 @@
             ..fileOffset = offset)
         ..fileOffset = fileOffset;
     } else {
-      VariableDeclaration variable = _helper.forest
-          .createVariableDeclarationForValue(receiver.fileOffset, receiver);
+      VariableDeclaration variable =
+          _helper.forest.createVariableDeclarationForValue(receiver);
       Expression read =
           _createRead(_helper.createVariableGet(variable, receiver.fileOffset));
       Expression write = _createWrite(fileOffset,
@@ -2136,8 +2127,8 @@
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
     if (isNullAware) {
-      VariableDeclaration variable = _helper.forest
-          .createVariableDeclarationForValue(receiver.fileOffset, receiver);
+      VariableDeclaration variable =
+          _helper.forest.createVariableDeclarationForValue(receiver);
       MethodInvocation binary = _helper.forest.createMethodInvocation(
           offset,
           _createRead(_helper.createVariableGet(variable, receiver.fileOffset)),
@@ -2149,8 +2140,8 @@
           forEffect: voidContext, readOnlyReceiver: true);
       return new NullAwareExtension(variable, write)..fileOffset = offset;
     } else {
-      VariableDeclaration variable = _helper.forest
-          .createVariableDeclarationForValue(receiver.fileOffset, receiver);
+      VariableDeclaration variable =
+          _helper.forest.createVariableDeclarationForValue(receiver);
       MethodInvocation binary = _helper.forest.createMethodInvocation(
           offset,
           _createRead(_helper.createVariableGet(variable, receiver.fileOffset)),
@@ -2169,7 +2160,7 @@
       {int offset = TreeNode.noOffset,
       bool voidContext = false,
       Procedure interfaceTarget}) {
-    Expression value = _forest.createIntLiteral(1, null)..fileOffset = offset;
+    Expression value = _forest.createIntLiteral(offset, 1);
     if (voidContext) {
       return buildCompoundAssignment(binaryOperator, value,
           offset: offset,
@@ -2177,13 +2168,11 @@
           interfaceTarget: interfaceTarget,
           isPostIncDec: true);
     } else if (isNullAware) {
-      VariableDeclaration variable = _helper.forest
-          .createVariableDeclarationForValue(receiver.fileOffset, receiver);
+      VariableDeclaration variable =
+          _helper.forest.createVariableDeclarationForValue(receiver);
       VariableDeclaration read = _helper.forest
-          .createVariableDeclarationForValue(
-              fileOffset,
-              _createRead(
-                  _helper.createVariableGet(variable, receiver.fileOffset)));
+          .createVariableDeclarationForValue(_createRead(
+              _helper.createVariableGet(variable, receiver.fileOffset)));
       MethodInvocation binary = _helper.forest.createMethodInvocation(
           offset,
           _helper.createVariableGet(read, fileOffset),
@@ -2191,26 +2180,19 @@
           _helper.forest.createArguments(offset, <Expression>[value]),
           interfaceTarget: interfaceTarget);
       VariableDeclaration write = _helper.forest
-          .createVariableDeclarationForValue(
-              offset,
-              _createWrite(
-                  fileOffset,
-                  _helper.createVariableGet(variable, receiver.fileOffset),
-                  binary,
-                  forEffect: voidContext,
-                  readOnlyReceiver: true)
-                ..fileOffset = fileOffset);
+          .createVariableDeclarationForValue(_createWrite(fileOffset,
+              _helper.createVariableGet(variable, receiver.fileOffset), binary,
+              forEffect: voidContext, readOnlyReceiver: true)
+            ..fileOffset = fileOffset);
       return new NullAwareExtension(
           variable, new LocalPostIncDec(read, write)..fileOffset = offset)
         ..fileOffset = fileOffset;
     } else {
-      VariableDeclaration variable = _helper.forest
-          .createVariableDeclarationForValue(receiver.fileOffset, receiver);
+      VariableDeclaration variable =
+          _helper.forest.createVariableDeclarationForValue(receiver);
       VariableDeclaration read = _helper.forest
-          .createVariableDeclarationForValue(
-              fileOffset,
-              _createRead(
-                  _helper.createVariableGet(variable, receiver.fileOffset)));
+          .createVariableDeclarationForValue(_createRead(
+              _helper.createVariableGet(variable, receiver.fileOffset)));
       MethodInvocation binary = _helper.forest.createMethodInvocation(
           offset,
           _helper.createVariableGet(read, fileOffset),
@@ -2218,15 +2200,10 @@
           _helper.forest.createArguments(offset, <Expression>[value]),
           interfaceTarget: interfaceTarget);
       VariableDeclaration write = _helper.forest
-          .createVariableDeclarationForValue(
-              offset,
-              _createWrite(
-                  fileOffset,
-                  _helper.createVariableGet(variable, receiver.fileOffset),
-                  binary,
-                  forEffect: voidContext,
-                  readOnlyReceiver: true)
-                ..fileOffset = fileOffset);
+          .createVariableDeclarationForValue(_createWrite(fileOffset,
+              _helper.createVariableGet(variable, receiver.fileOffset), binary,
+              forEffect: voidContext, readOnlyReceiver: true)
+            ..fileOffset = fileOffset);
       return new PropertyPostIncDec(variable, read, write)..fileOffset = offset;
     }
   }
@@ -2236,8 +2213,8 @@
     VariableDeclaration receiverVariable;
     Expression receiverExpression = receiver;
     if (isNullAware) {
-      receiverVariable = _helper.forest
-          .createVariableDeclarationForValue(receiver.fileOffset, receiver);
+      receiverVariable =
+          _helper.forest.createVariableDeclarationForValue(receiver);
       receiverExpression = _helper.createVariableGet(
           receiverVariable, receiverVariable.fileOffset);
     }
@@ -2455,7 +2432,7 @@
       {int offset = TreeNode.noOffset,
       bool voidContext = false,
       Procedure interfaceTarget}) {
-    Expression value = _forest.createIntLiteral(1, null)..fileOffset = offset;
+    Expression value = _forest.createIntLiteral(offset, 1);
     return buildCompoundAssignment(binaryOperator, value,
         offset: offset,
         voidContext: voidContext,
@@ -2710,7 +2687,7 @@
       {int offset = TreeNode.noOffset,
       bool voidContext = false,
       Procedure interfaceTarget}) {
-    Expression value = _forest.createIntLiteral(1, null)..fileOffset = offset;
+    Expression value = _forest.createIntLiteral(offset, 1);
     return buildCompoundAssignment(binaryOperator, value,
         offset: offset,
         voidContext: voidContext,
@@ -3002,14 +2979,14 @@
             declaration.message.messageObject, fileOffset, token.length);
       } else {
         super.expression = _forest.createTypeLiteral(
+            offsetForToken(token),
             _helper.buildDartType(
                 new UnresolvedType(
                     buildTypeWithResolvedArguments(
                         _helper.libraryBuilder.nonNullableBuilder, null),
                     fileOffset,
                     _uri),
-                nonInstanceAccessIsError: true),
-            token);
+                nonInstanceAccessIsError: true));
       }
     }
     return super.expression;
@@ -3190,7 +3167,7 @@
       {int offset = TreeNode.noOffset,
       bool voidContext = false,
       Procedure interfaceTarget}) {
-    Expression value = _forest.createIntLiteral(1, null)..fileOffset = offset;
+    Expression value = _forest.createIntLiteral(offset, 1);
     return buildCompoundAssignment(binaryOperator, value,
         offset: offset,
         voidContext: voidContext,
@@ -3281,9 +3258,8 @@
   Expression buildPrefixIncrement(Name binaryOperator,
       {int offset: -1, bool voidContext: false, Procedure interfaceTarget}) {
     return buildError(
-        _forest.createArguments(fileOffset, <Expression>[
-          _forest.createIntLiteral(1, null)..fileOffset = offset
-        ]),
+        _forest.createArguments(
+            fileOffset, <Expression>[_forest.createIntLiteral(offset, 1)]),
         isGetter: true)
       ..fileOffset = offset;
   }
@@ -3292,9 +3268,8 @@
   Expression buildPostfixIncrement(Name binaryOperator,
       {int offset: -1, bool voidContext: false, Procedure interfaceTarget}) {
     return buildError(
-        _forest.createArguments(fileOffset, <Expression>[
-          _forest.createIntLiteral(1, null)..fileOffset = offset
-        ]),
+        _forest.createArguments(
+            fileOffset, <Expression>[_forest.createIntLiteral(offset, 1)]),
         isGetter: true)
       ..fileOffset = offset;
   }
@@ -3374,12 +3349,8 @@
       {bool isGetter: false, bool isSetter: false, int offset}) {
     offset ??= fileOffset;
     return _helper.throwNoSuchMethodError(
-        _forest.createNullLiteral(null)..fileOffset = offset,
-        _plainNameForRead,
-        arguments,
-        offset,
-        isGetter: isGetter,
-        isSetter: isSetter);
+        _forest.createNullLiteral(offset), _plainNameForRead, arguments, offset,
+        isGetter: isGetter, isSetter: isSetter);
   }
 
   @override
@@ -3467,8 +3438,8 @@
   @override
   Expression buildIfNullAssignment(Expression value, DartType type, int offset,
       {bool voidContext: false}) {
-    VariableDeclaration variable = _helper.forest
-        .createVariableDeclarationForValue(receiver.fileOffset, receiver);
+    VariableDeclaration variable =
+        _helper.forest.createVariableDeclarationForValue(receiver);
     PropertyGet read = new PropertyGet(
         _helper.createVariableGet(variable, receiver.fileOffset), name)
       ..fileOffset = fileOffset;
@@ -3486,8 +3457,8 @@
       Procedure interfaceTarget,
       bool isPreIncDec: false,
       bool isPostIncDec: false}) {
-    VariableDeclaration variable = _helper.forest
-        .createVariableDeclarationForValue(receiver.fileOffset, receiver);
+    VariableDeclaration variable =
+        _helper.forest.createVariableDeclarationForValue(receiver);
     MethodInvocation binary = _helper.forest.createMethodInvocation(
         offset,
         new PropertyGet(
@@ -3507,7 +3478,7 @@
       {int offset = TreeNode.noOffset,
       bool voidContext = false,
       Procedure interfaceTarget}) {
-    Expression value = _forest.createIntLiteral(1, null)..fileOffset = offset;
+    Expression value = _forest.createIntLiteral(offset, 1);
     if (voidContext) {
       return buildCompoundAssignment(binaryOperator, value,
           offset: offset,
@@ -3515,10 +3486,9 @@
           interfaceTarget: interfaceTarget,
           isPostIncDec: true);
     }
-    VariableDeclaration variable = _helper.forest
-        .createVariableDeclarationForValue(receiver.fileOffset, receiver);
+    VariableDeclaration variable =
+        _helper.forest.createVariableDeclarationForValue(receiver);
     VariableDeclaration read = _helper.forest.createVariableDeclarationForValue(
-        fileOffset,
         new PropertyGet(
             _helper.createVariableGet(variable, receiver.fileOffset), name)
           ..fileOffset = fileOffset);
@@ -3529,14 +3499,12 @@
         _helper.forest.createArguments(offset, <Expression>[value]),
         interfaceTarget: interfaceTarget);
     VariableDeclaration write = _helper.forest
-        .createVariableDeclarationForValue(
-            offset,
-            _helper.forest.createPropertySet(
-                fileOffset,
-                _helper.createVariableGet(variable, receiver.fileOffset),
-                name,
-                binary,
-                forEffect: true));
+        .createVariableDeclarationForValue(_helper.forest.createPropertySet(
+            fileOffset,
+            _helper.createVariableGet(variable, receiver.fileOffset),
+            name,
+            binary,
+            forEffect: true));
     return new PropertyPostIncDec(variable, read, write)..fileOffset = offset;
   }
 
@@ -3923,11 +3891,8 @@
 
   @override
   Expression doInvocation(int offset, Arguments arguments) {
-    return _helper.throwNoSuchMethodError(
-        _forest.createNullLiteral(null)..fileOffset = offset,
-        _plainNameForRead,
-        arguments,
-        fileOffset);
+    return _helper.throwNoSuchMethodError(_forest.createNullLiteral(offset),
+        _plainNameForRead, arguments, fileOffset);
   }
 
   @override
@@ -4239,7 +4204,7 @@
     if (message != null) {
       return _helper.buildInvalidInitializer(
           _helper.throwNoSuchMethodError(
-              _forest.createNullLiteral(null)..fileOffset = offset,
+              _forest.createNullLiteral(offset),
               _helper.constructorNameForDiagnostics(name.name,
                   isSuper: isSuper),
               arguments,
@@ -4556,8 +4521,8 @@
 
 Expression buildIsNull(
     Expression value, int offset, ExpressionGeneratorHelper helper) {
-  return makeBinary(value, equalsName, null,
-      helper.forest.createNullLiteral(null)..fileOffset = offset, helper,
+  return makeBinary(
+      value, equalsName, null, helper.forest.createNullLiteral(offset), helper,
       offset: offset);
 }
 
diff --git a/pkg/front_end/lib/src/fasta/kernel/forest.dart b/pkg/front_end/lib/src/fasta/kernel/forest.dart
index 1a26c43..dc4369b 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forest.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forest.dart
@@ -10,12 +10,8 @@
 
 import '../names.dart';
 
-import '../parser.dart' show offsetForToken, optional;
-
 import '../problems.dart' show unsupported;
 
-import '../scanner.dart' show Token;
-
 import 'collections.dart'
     show
         ForElement,
@@ -47,6 +43,7 @@
       List<DartType> typeArguments = const <DartType>[],
       List<Expression> positionalArguments = const <Expression>[],
       List<NamedExpression> namedArguments = const <NamedExpression>[]}) {
+    assert(fileOffset != null);
     return new ArgumentsImpl.forExtensionMethod(
         extensionTypeParameterCount, typeParameterCount, receiver,
         extensionTypeArguments: extensionTypeArguments,
@@ -57,6 +54,7 @@
   }
 
   Arguments createArgumentsEmpty(int fileOffset) {
+    assert(fileOffset != null);
     return createArguments(fileOffset, <Expression>[]);
   }
 
@@ -76,283 +74,236 @@
     ArgumentsImpl.setNonInferrableArgumentTypes(arguments, types);
   }
 
-  StringLiteral asLiteralString(Expression value) => value;
+  /// Return a representation of a boolean literal at the given [fileOffset].
+  /// The literal has the given [value].
+  BoolLiteral createBoolLiteral(int fileOffset, bool value) {
+    assert(fileOffset != null);
+    return new BoolLiteral(value)..fileOffset = fileOffset;
+  }
 
-  /// Return a representation of a boolean literal at the given [location]. The
+  /// Return a representation of a double literal at the given [fileOffset]. The
   /// literal has the given [value].
-  BoolLiteral createBoolLiteral(bool value, Token token) {
-    return new BoolLiteral(value)..fileOffset = offsetForToken(token);
+  DoubleLiteral createDoubleLiteral(int fileOffset, double value) {
+    assert(fileOffset != null);
+    return new DoubleLiteral(value)..fileOffset = fileOffset;
   }
 
-  /// Return a representation of a double literal at the given [location]. The
-  /// literal has the given [value].
-  DoubleLiteral createDoubleLiteral(double value, Token token) {
-    return new DoubleLiteral(value)..fileOffset = offsetForToken(token);
+  /// Return a representation of an integer literal at the given [fileOffset].
+  /// The literal has the given [value].
+  IntLiteral createIntLiteral(int fileOffset, int value, [String literal]) {
+    assert(fileOffset != null);
+    return new IntJudgment(value, literal)..fileOffset = fileOffset;
   }
 
-  /// Return a representation of an integer literal at the given [location]. The
-  /// literal has the given [value].
-  IntLiteral createIntLiteral(int value, Token token) {
-    return new IntJudgment(value, token?.lexeme)
-      ..fileOffset = offsetForToken(token);
+  IntLiteral createIntLiteralLarge(int fileOffset, String literal) {
+    assert(fileOffset != null);
+    return new ShadowLargeIntLiteral(literal, fileOffset);
   }
 
-  IntLiteral createIntLiteralLarge(String literal, Token token) {
-    return new ShadowLargeIntLiteral(literal, offsetForToken(token));
-  }
-
-  /// Return a representation of a list literal. The [constKeyword] is the
-  /// location of the `const` keyword, or `null` if there is no keyword. The
+  /// Return a representation of a list literal at the given [fileOffset]. The
   /// [isConst] is `true` if the literal is either explicitly or implicitly a
   /// constant. The [typeArgument] is the representation of the single valid
   /// type argument preceding the list literal, or `null` if there is no type
   /// argument, there is more than one type argument, or if the type argument
-  /// cannot be resolved. The [typeArguments] is the representation of all of
-  /// the type arguments preceding the list literal, or `null` if there are no
-  /// type arguments. The [leftBracket] is the location of the `[`. The list of
-  /// [expressions] is a list of the representations of the list elements. The
-  /// [rightBracket] is the location of the `]`.
+  /// cannot be resolved. The list of [expressions] is a list of the
+  /// representations of the list elements.
   ListLiteral createListLiteral(
-      Token constKeyword,
-      bool isConst,
-      Object typeArgument,
-      Object typeArguments,
-      Token leftBracket,
-      List<Expression> expressions,
-      Token rightBracket) {
-    // TODO(brianwilkerson): The file offset computed below will not be correct
-    // if there are type arguments but no `const` keyword.
+      int fileOffset, DartType typeArgument, List<Expression> expressions,
+      {bool isConst}) {
+    assert(fileOffset != null);
+    assert(isConst != null);
     return new ListLiteral(expressions,
         typeArgument: typeArgument, isConst: isConst)
-      ..fileOffset = offsetForToken(constKeyword ?? leftBracket);
+      ..fileOffset = fileOffset;
   }
 
-  /// Return a representation of a set literal. The [constKeyword] is the
-  /// location of the `const` keyword, or `null` if there is no keyword. The
+  /// Return a representation of a set literal at the given [fileOffset]. The
   /// [isConst] is `true` if the literal is either explicitly or implicitly a
   /// constant. The [typeArgument] is the representation of the single valid
   /// type argument preceding the set literal, or `null` if there is no type
   /// argument, there is more than one type argument, or if the type argument
-  /// cannot be resolved. The [typeArguments] is the representation of all of
-  /// the type arguments preceding the set literal, or `null` if there are no
-  /// type arguments. The [leftBrace] is the location of the `{`. The list of
-  /// [expressions] is a list of the representations of the set elements. The
-  /// [rightBrace] is the location of the `}`.
+  /// cannot be resolved. The list of [expressions] is a list of the
+  /// representations of the set elements.
   SetLiteral createSetLiteral(
-      Token constKeyword,
-      bool isConst,
-      Object typeArgument,
-      Object typeArguments,
-      Token leftBrace,
-      List<Expression> expressions,
-      Token rightBrace) {
-    // TODO(brianwilkerson): The file offset computed below will not be correct
-    // if there are type arguments but no `const` keyword.
+      int fileOffset, DartType typeArgument, List<Expression> expressions,
+      {bool isConst}) {
+    assert(fileOffset != null);
+    assert(isConst != null);
     return new SetLiteral(expressions,
         typeArgument: typeArgument, isConst: isConst)
-      ..fileOffset = offsetForToken(constKeyword ?? leftBrace);
+      ..fileOffset = fileOffset;
   }
 
-  /// Return a representation of a map literal. The [constKeyword] is the
-  /// location of the `const` keyword, or `null` if there is no keyword. The
+  /// Return a representation of a map literal at the given [fileOffset]. The
   /// [isConst] is `true` if the literal is either explicitly or implicitly a
   /// constant. The [keyType] is the representation of the first type argument
   /// preceding the map literal, or `null` if there are not exactly two type
   /// arguments or if the first type argument cannot be resolved. The
   /// [valueType] is the representation of the second type argument preceding
   /// the map literal, or `null` if there are not exactly two type arguments or
-  /// if the second type argument cannot be resolved. The [typeArguments] is the
-  /// representation of all of the type arguments preceding the map literal, or
-  /// `null` if there are no type arguments. The [leftBrace] is the location
-  /// of the `{`. The list of [entries] is a list of the representations of the
-  /// map entries. The [rightBrace] is the location of the `}`.
-  MapLiteral createMapLiteral(
-      Token constKeyword,
-      bool isConst,
-      DartType keyType,
-      DartType valueType,
-      Object typeArguments,
-      Token leftBrace,
-      List<MapEntry> entries,
-      Token rightBrace) {
-    // TODO(brianwilkerson): The file offset computed below will not be correct
-    // if there are type arguments but no `const` keyword.
+  /// if the second type argument cannot be resolved. The list of [entries] is a
+  /// list of the representations of the map entries.
+  MapLiteral createMapLiteral(int fileOffset, DartType keyType,
+      DartType valueType, List<MapEntry> entries,
+      {bool isConst}) {
+    assert(fileOffset != null);
+    assert(isConst != null);
     return new MapLiteral(entries,
         keyType: keyType, valueType: valueType, isConst: isConst)
-      ..fileOffset = offsetForToken(constKeyword ?? leftBrace);
+      ..fileOffset = fileOffset;
   }
 
   /// Return a representation of a null literal at the given [fileOffset].
   NullLiteral createNullLiteral(int fileOffset) {
-    return new NullLiteral()..fileOffset = fileOffset ?? TreeNode.noOffset;
+    assert(fileOffset != null);
+    return new NullLiteral()..fileOffset = fileOffset;
   }
 
   /// Return a representation of a simple string literal at the given
-  /// [location]. The literal has the given [value]. This does not include
+  /// [fileOffset]. The literal has the given [value]. This does not include
   /// either adjacent strings or interpolated strings.
-  StringLiteral createStringLiteral(String value, Token token) {
-    return new StringLiteral(value)..fileOffset = offsetForToken(token);
+  StringLiteral createStringLiteral(int fileOffset, String value) {
+    assert(fileOffset != null);
+    return new StringLiteral(value)..fileOffset = fileOffset;
   }
 
-  /// Return a representation of a symbol literal defined by [value].
-  SymbolLiteral createSymbolLiteral(String value, Token token) {
-    return new SymbolLiteral(value)..fileOffset = offsetForToken(token);
+  /// Return a representation of a symbol literal defined by [value] at the
+  /// given [fileOffset].
+  SymbolLiteral createSymbolLiteral(int fileOffset, String value) {
+    assert(fileOffset != null);
+    return new SymbolLiteral(value)..fileOffset = fileOffset;
   }
 
-  TypeLiteral createTypeLiteral(DartType type, Token token) {
-    return new TypeLiteral(type)..fileOffset = offsetForToken(token);
+  TypeLiteral createTypeLiteral(int fileOffset, DartType type) {
+    assert(fileOffset != null);
+    return new TypeLiteral(type)..fileOffset = fileOffset;
   }
 
-  /// Return a representation of a key/value pair in a literal map. The [key] is
-  /// the representation of the expression used to compute the key. The [colon]
-  /// is the location of the colon separating the key and the value. The [value]
-  /// is the representation of the expression used to compute the value.
-  MapEntry createMapEntry(Expression key, Token colon, Expression value) {
-    return new MapEntry(key, value)..fileOffset = offsetForToken(colon);
+  /// Return a representation of a key/value pair in a literal map at the given
+  /// [fileOffset]. The [key] is the representation of the expression used to
+  /// compute the key. The [value] is the representation of the expression used
+  /// to compute the value.
+  MapEntry createMapEntry(int fileOffset, Expression key, Expression value) {
+    assert(fileOffset != null);
+    return new MapEntry(key, value)..fileOffset = fileOffset;
   }
 
-  int readOffset(TreeNode node) => node.fileOffset;
-
   Expression createLoadLibrary(
-      LibraryDependency dependency, Arguments arguments) {
-    return new LoadLibraryImpl(dependency, arguments);
+      int fileOffset, LibraryDependency dependency, Arguments arguments) {
+    assert(fileOffset != null);
+    return new LoadLibraryImpl(dependency, arguments)..fileOffset = fileOffset;
   }
 
-  Expression checkLibraryIsLoaded(LibraryDependency dependency) {
-    return new CheckLibraryIsLoaded(dependency);
+  Expression checkLibraryIsLoaded(
+      int fileOffset, LibraryDependency dependency) {
+    assert(fileOffset != null);
+    return new CheckLibraryIsLoaded(dependency)..fileOffset = fileOffset;
   }
 
   Expression createAsExpression(
-      Expression expression, DartType type, Token token) {
-    return new AsExpression(expression, type)
-      ..fileOffset = offsetForToken(token);
+      int fileOffset, Expression expression, DartType type) {
+    assert(fileOffset != null);
+    return new AsExpression(expression, type)..fileOffset = fileOffset;
   }
 
-  Expression createSpreadElement(Expression expression, Token token) {
-    return new SpreadElement(expression, token.lexeme == '...?')
-      ..fileOffset = offsetForToken(token);
+  Expression createSpreadElement(int fileOffset, Expression expression,
+      {bool isNullAware}) {
+    assert(fileOffset != null);
+    assert(isNullAware != null);
+    return new SpreadElement(expression, isNullAware)..fileOffset = fileOffset;
   }
 
-  Expression createIfElement(Expression condition, Expression then,
-      Expression otherwise, Token token) {
-    return new IfElement(condition, then, otherwise)
-      ..fileOffset = offsetForToken(token);
+  Expression createIfElement(
+      int fileOffset, Expression condition, Expression then,
+      [Expression otherwise]) {
+    assert(fileOffset != null);
+    return new IfElement(condition, then, otherwise)..fileOffset = fileOffset;
   }
 
-  MapEntry createIfMapEntry(
-      Expression condition, MapEntry then, MapEntry otherwise, Token token) {
-    return new IfMapEntry(condition, then, otherwise)
-      ..fileOffset = offsetForToken(token);
+  MapEntry createIfMapEntry(int fileOffset, Expression condition, MapEntry then,
+      [MapEntry otherwise]) {
+    assert(fileOffset != null);
+    return new IfMapEntry(condition, then, otherwise)..fileOffset = fileOffset;
   }
 
   Expression createForElement(
+      int fileOffset,
       List<VariableDeclaration> variables,
       Expression condition,
       List<Expression> updates,
-      Expression body,
-      Token token) {
+      Expression body) {
+    assert(fileOffset != null);
     return new ForElement(variables, condition, updates, body)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
   }
 
   MapEntry createForMapEntry(
+      int fileOffset,
       List<VariableDeclaration> variables,
       Expression condition,
       List<Expression> updates,
-      MapEntry body,
-      Token token) {
+      MapEntry body) {
+    assert(fileOffset != null);
     return new ForMapEntry(variables, condition, updates, body)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
   }
 
   Expression createForInElement(
+      int fileOffset,
       VariableDeclaration variable,
       Expression iterable,
       Statement prologue,
       Expression body,
       Expression problem,
-      Token token,
       {bool isAsync: false}) {
+    assert(fileOffset != null);
     return new ForInElement(variable, iterable, prologue, body, problem,
         isAsync: isAsync)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
   }
 
   MapEntry createForInMapEntry(
+      int fileOffset,
       VariableDeclaration variable,
       Expression iterable,
       Statement prologue,
       MapEntry body,
       Expression problem,
-      Token token,
       {bool isAsync: false}) {
+    assert(fileOffset != null);
     return new ForInMapEntry(variable, iterable, prologue, body, problem,
         isAsync: isAsync)
-      ..fileOffset = offsetForToken(token);
+      ..fileOffset = fileOffset;
   }
 
   /// Return a representation of an assert that appears in a constructor's
   /// initializer list.
   AssertInitializer createAssertInitializer(
-      Token assertKeyword,
-      Token leftParenthesis,
-      Expression condition,
-      Token comma,
-      Expression message) {
-    return new AssertInitializer(createAssertStatement(
-        assertKeyword, leftParenthesis, condition, comma, message, null));
+      int fileOffset, AssertStatement assertStatement) {
+    assert(fileOffset != null);
+    return new AssertInitializer(assertStatement)..fileOffset = fileOffset;
   }
 
   /// Return a representation of an assert that appears as a statement.
-  Statement createAssertStatement(Token assertKeyword, Token leftParenthesis,
-      Expression condition, Token comma, Expression message, Token semicolon) {
-    // Compute start and end offsets for the condition expression.
-    // This code is a temporary workaround because expressions don't carry
-    // their start and end offsets currently.
-    //
-    // The token that follows leftParenthesis is considered to be the
-    // first token of the condition.
-    // TODO(ahe): this really should be condition.fileOffset.
-    int startOffset = leftParenthesis.next.offset;
-    int endOffset;
-    {
-      // Search forward from leftParenthesis to find the last token of
-      // the condition - which is a token immediately followed by a commaToken,
-      // right parenthesis or a trailing comma.
-      Token conditionBoundary = comma ?? leftParenthesis.endGroup;
-      Token conditionLastToken = leftParenthesis;
-      while (!conditionLastToken.isEof) {
-        Token nextToken = conditionLastToken.next;
-        if (nextToken == conditionBoundary) {
-          break;
-        } else if (optional(',', nextToken) &&
-            nextToken.next == conditionBoundary) {
-          // The next token is trailing comma, which means current token is
-          // the last token of the condition.
-          break;
-        }
-        conditionLastToken = nextToken;
-      }
-      if (conditionLastToken.isEof) {
-        endOffset = startOffset = -1;
-      } else {
-        endOffset = conditionLastToken.offset + conditionLastToken.length;
-      }
-    }
+  Statement createAssertStatement(int fileOffset, Expression condition,
+      Expression message, int conditionStartOffset, int conditionEndOffset) {
+    assert(fileOffset != null);
     return new AssertStatement(condition,
-        conditionStartOffset: startOffset,
-        conditionEndOffset: endOffset,
-        message: message);
+        conditionStartOffset: conditionStartOffset,
+        conditionEndOffset: conditionEndOffset,
+        message: message)
+      ..fileOffset = fileOffset;
   }
 
-  Expression createAwaitExpression(Expression operand, Token token) {
-    return new AwaitExpression(operand)..fileOffset = offsetForToken(token);
+  Expression createAwaitExpression(int fileOffset, Expression operand) {
+    assert(fileOffset != null);
+    return new AwaitExpression(operand)..fileOffset = fileOffset;
   }
 
-  /// Return a representation of a block of [statements] enclosed between the
-  /// [openBracket] and [closeBracket].
-  Statement createBlock(
-      Token openBrace, List<Statement> statements, Token closeBrace) {
+  /// Return a representation of a block of [statements] at the given
+  /// [fileOffset].
+  Statement createBlock(int fileOffset, List<Statement> statements) {
+    assert(fileOffset != null);
     List<Statement> copy;
     for (int i = 0; i < statements.length; i++) {
       Statement statement = statements[i];
@@ -363,178 +314,180 @@
         copy.add(statement);
       }
     }
-    return new Block(copy ?? statements)
-      ..fileOffset = offsetForToken(openBrace);
+    return new Block(copy ?? statements)..fileOffset = fileOffset;
   }
 
   /// Return a representation of a break statement.
-  Statement createBreakStatement(
-      Token breakKeyword, Object label, Token semicolon) {
-    return new BreakStatement(null)..fileOffset = breakKeyword.charOffset;
+  Statement createBreakStatement(int fileOffset, Object label) {
+    assert(fileOffset != null);
+    // TODO(johnniwinther): Use [label]?
+    return new BreakStatement(null)..fileOffset = fileOffset;
   }
 
   /// Return a representation of a catch clause.
   Catch createCatch(
-      Token onKeyword,
+      int fileOffset,
       DartType exceptionType,
-      Token catchKeyword,
       VariableDeclaration exceptionParameter,
       VariableDeclaration stackTraceParameter,
       DartType stackTraceType,
       Statement body) {
+    assert(fileOffset != null);
     return new Catch(exceptionParameter, body,
         guard: exceptionType, stackTrace: stackTraceParameter)
-      ..fileOffset = offsetForToken(onKeyword ?? catchKeyword);
+      ..fileOffset = fileOffset;
   }
 
-  /// Return a representation of a conditional expression. The [condition] is
-  /// the expression preceding the question mark. The [question] is the `?`. The
-  /// [thenExpression] is the expression following the question mark. The
-  /// [colon] is the `:`. The [elseExpression] is the expression following the
-  /// colon.
-  Expression createConditionalExpression(Expression condition, Token question,
-      Expression thenExpression, Token colon, Expression elseExpression) {
+  /// Return a representation of a conditional expression at the given
+  /// [fileOffset]. The [condition] is the expression preceding the question
+  /// mark. The [thenExpression] is the expression following the question mark.
+  /// The [elseExpression] is the expression following the colon.
+  Expression createConditionalExpression(int fileOffset, Expression condition,
+      Expression thenExpression, Expression elseExpression) {
     return new ConditionalExpression(
         condition, thenExpression, elseExpression, null)
-      ..fileOffset = offsetForToken(question);
+      ..fileOffset = fileOffset;
   }
 
   /// Return a representation of a continue statement.
-  Statement createContinueStatement(
-      Token continueKeyword, Object label, Token semicolon) {
-    return new BreakStatement(null)..fileOffset = continueKeyword.charOffset;
+  Statement createContinueStatement(int fileOffset, Object label) {
+    assert(fileOffset != null);
+    // TODO(johnniwinther): Use [label]?
+    return new BreakStatement(null)..fileOffset = fileOffset;
   }
 
   /// Return a representation of a do statement.
-  Statement createDoStatement(Token doKeyword, Statement body,
-      Token whileKeyword, Expression condition, Token semicolon) {
-    return new DoStatement(body, condition)..fileOffset = doKeyword.charOffset;
+  Statement createDoStatement(
+      int fileOffset, Statement body, Expression condition) {
+    assert(fileOffset != null);
+    return new DoStatement(body, condition)..fileOffset = fileOffset;
   }
 
-  /// Return a representation of an expression statement composed from the
-  /// [expression] and [semicolon].
-  Statement createExpressionStatement(Expression expression, Token semicolon) {
-    return new ExpressionStatement(expression);
+  /// Return a representation of an expression statement at the given
+  /// [fileOffset] containing the [expression].
+  Statement createExpressionStatement(int fileOffset, Expression expression) {
+    assert(fileOffset != null);
+    return new ExpressionStatement(expression)..fileOffset = fileOffset;
   }
 
-  /// Return a representation of an empty statement consisting of the given
-  /// [semicolon].
-  Statement createEmptyStatement(Token semicolon) {
-    return new EmptyStatement();
+  /// Return a representation of an empty statement  at the given [fileOffset].
+  Statement createEmptyStatement(int fileOffset) {
+    assert(fileOffset != null);
+    return new EmptyStatement()..fileOffset = fileOffset;
   }
 
   /// Return a representation of a for statement.
   Statement createForStatement(
-      Token forKeyword,
-      Token leftParenthesis,
+      int fileOffset,
       List<VariableDeclaration> variables,
-      Token leftSeparator,
       Expression condition,
       Statement conditionStatement,
       List<Expression> updaters,
-      Token rightParenthesis,
       Statement body) {
+    assert(fileOffset != null);
     return new ForStatement(variables ?? [], condition, updaters, body)
-      ..fileOffset = forKeyword.charOffset;
+      ..fileOffset = fileOffset;
   }
 
   /// Return a representation of an `if` statement.
-  Statement createIfStatement(Token ifKeyword, Expression condition,
-      Statement thenStatement, Token elseKeyword, Statement elseStatement) {
+  Statement createIfStatement(int fileOffset, Expression condition,
+      Statement thenStatement, Statement elseStatement) {
+    assert(fileOffset != null);
     return new IfStatement(condition, thenStatement, elseStatement)
-      ..fileOffset = ifKeyword.charOffset;
+      ..fileOffset = fileOffset;
   }
 
-  /// Return a representation of an `is` expression. The [operand] is the
-  /// representation of the left operand. The [isOperator] is the `is` operator.
-  /// The [notOperator] is either the `!` or `null` if the test is not negated.
-  /// The [type] is a representation of the type that is the right operand.
+  /// Return a representation of an `is` expression at the given [fileOffset].
+  /// The [operand] is the representation of the left operand. The [type] is a
+  /// representation of the type that is the right operand. If [notFileOffset]
+  /// is non-null the test is negated the that file offset.
   Expression createIsExpression(
-      Expression operand, Token isOperator, Token notOperator, DartType type) {
+      int fileOffset, Expression operand, DartType type,
+      {int notFileOffset}) {
+    assert(fileOffset != null);
     Expression result = new IsExpression(operand, type)
-      ..fileOffset = offsetForToken(isOperator);
-    if (notOperator != null) {
-      result = createNot(result, notOperator, false);
+      ..fileOffset = fileOffset;
+    if (notFileOffset != null) {
+      result = createNot(notFileOffset, result);
     }
     return result;
   }
 
-  /// Return a representation of a logical expression having the [leftOperand],
-  /// [rightOperand] and the [operator] (either `&&` or `||`).
-  Expression createLogicalExpression(
-      Expression leftOperand, Token operator, Expression rightOperand) {
-    return new LogicalExpression(
-        leftOperand, operator.stringValue, rightOperand)
-      ..fileOffset = offsetForToken(operator);
+  /// Return a representation of a logical expression at the given [fileOffset]
+  /// having the [leftOperand], [rightOperand] and the [operator]
+  /// (either `&&` or `||`).
+  Expression createLogicalExpression(int fileOffset, Expression leftOperand,
+      String operator, Expression rightOperand) {
+    assert(fileOffset != null);
+    assert(operator == '&&' || operator == '||');
+    return new LogicalExpression(leftOperand, operator, rightOperand)
+      ..fileOffset = fileOffset;
   }
 
-  Expression createNot(Expression operand, Token token, bool isSynthetic) {
-    return new Not(operand)..fileOffset = offsetForToken(token);
-  }
-
-  /// Return a representation of a parenthesized condition consisting of the
-  /// given [expression] between the [leftParenthesis] and [rightParenthesis].
-  Expression createParenthesizedCondition(
-      Token leftParenthesis, Expression expression, Token rightParenthesis) {
-    return expression;
+  Expression createNot(int fileOffset, Expression operand) {
+    assert(fileOffset != null);
+    return new Not(operand)..fileOffset = fileOffset;
   }
 
   /// Return a representation of a rethrow statement consisting of the
-  /// [rethrowKeyword] followed by the [semicolon].
-  Statement createRethrowStatement(Token rethrowKeyword, Token semicolon) {
+  /// rethrow at [rethrowFileOffset] and the statement at [statementFileOffset].
+  Statement createRethrowStatement(
+      int rethrowFileOffset, int statementFileOffset) {
+    assert(rethrowFileOffset != null);
+    assert(statementFileOffset != null);
     return new ExpressionStatement(
-        new Rethrow()..fileOffset = offsetForToken(rethrowKeyword));
+        new Rethrow()..fileOffset = rethrowFileOffset)
+      ..fileOffset = statementFileOffset;
   }
 
   /// Return a representation of a return statement.
   Statement createReturnStatement(int fileOffset, Expression expression,
       {bool isArrow: true}) {
+    assert(fileOffset != null);
     return new ReturnStatementImpl(isArrow, expression)
       ..fileOffset = fileOffset ?? TreeNode.noOffset;
   }
 
   Expression createStringConcatenation(
-      List<Expression> expressions, Token token) {
-    return new StringConcatenation(expressions)
-      ..fileOffset = offsetForToken(token);
+      int fileOffset, List<Expression> expressions) {
+    assert(fileOffset != null);
+    return new StringConcatenation(expressions)..fileOffset = fileOffset;
   }
 
   /// The given [statement] is being used as the target of either a break or
   /// continue statement. Return the statement that should be used as the actual
   /// target.
   Statement createLabeledStatement(Statement statement) {
-    return new LabeledStatement(statement);
+    return new LabeledStatement(statement)..fileOffset = statement.fileOffset;
   }
 
-  Expression createThisExpression(int offset) {
-    assert(offset != null);
-    return new ThisExpression()..fileOffset = offset;
+  Expression createThisExpression(int fileOffset) {
+    assert(fileOffset != null);
+    return new ThisExpression()..fileOffset = fileOffset;
   }
 
-  /// Return a representation of a throw expression consisting of the
-  /// [throwKeyword].
-  Expression createThrow(Token throwKeyword, Expression expression) {
-    return new Throw(expression)..fileOffset = offsetForToken(throwKeyword);
+  /// Return a representation of a throw expression at the given [fileOffset].
+  Expression createThrow(int fileOffset, Expression expression) {
+    assert(fileOffset != null);
+    return new Throw(expression)..fileOffset = fileOffset;
   }
 
   bool isThrow(Object o) => o is Throw;
 
-  /// Return a representation of a try statement. The statement is introduced by
-  /// the [tryKeyword] and the given [body]. If catch clauses were included,
-  /// then the [catchClauses] will represent them, otherwise it will be `null`.
-  /// Similarly, if a finally block was included, then the [finallyKeyword] and
-  /// [finallyBlock] will be non-`null`, otherwise both will be `null`. If there
-  /// was an error in some part of the try statement, then an [errorReplacement]
-  /// might be provided, in which case it could be returned instead of the
-  /// representation of the try statement.
-  Statement createTryStatement(Token tryKeyword, Statement body,
-      List<Catch> catchClauses, Token finallyKeyword, Statement finallyBlock) {
+  /// Return a representation of a try statement at the given [fileOffset].
+  /// The statement is introduced by the given [body]. If catch clauses were
+  /// included, then the [catchClauses] will represent them, otherwise it will
+  /// be `null`. Similarly, if a finally block was included, then the
+  /// [finallyBlock] will be non-`null`, otherwise both will be `null`.
+  Statement createTryStatement(int fileOffset, Statement body,
+      List<Catch> catchClauses, Statement finallyBlock) {
+    assert(fileOffset != null);
     Statement result = body;
     if (catchClauses != null) {
-      result = new TryCatch(result, catchClauses);
+      result = new TryCatch(result, catchClauses)..fileOffset = fileOffset;
     }
     if (finallyBlock != null) {
-      result = new TryFinally(result, finallyBlock);
+      result = new TryFinally(result, finallyBlock)..fileOffset = fileOffset;
     }
     return result;
   }
@@ -562,34 +515,27 @@
     }
   }
 
-  /// Return a representation of a while statement introduced by the
-  /// [whileKeyword] and consisting of the given [condition] and [body].
+  /// Return a representation of a while statement at the given [fileOffset]
+  /// consisting of the given [condition] and [body].
   Statement createWhileStatement(
-      Token whileKeyword, Expression condition, Statement body) {
-    return new WhileStatement(condition, body)
-      ..fileOffset = whileKeyword.charOffset;
+      int fileOffset, Expression condition, Statement body) {
+    assert(fileOffset != null);
+    return new WhileStatement(condition, body)..fileOffset = fileOffset;
   }
 
-  /// Return a representation of a yield statement consisting of the
-  /// [yieldKeyword], [star], [expression], and [semicolon]. The [star] is null
-  /// when no star was included in the source code.
-  Statement createYieldStatement(
-      Token yieldKeyword, Token star, Expression expression, Token semicolon) {
-    return new YieldStatement(expression, isYieldStar: star != null)
-      ..fileOffset = yieldKeyword.charOffset;
-  }
-
-  /// Return the expression from the given expression [statement].
-  Expression getExpressionFromExpressionStatement(Statement statement) {
-    return (statement as ExpressionStatement).expression;
+  /// Return a representation of a yield statement at the given [fileOffset]
+  /// of the given [expression]. If [isYieldStar] is `true` the created
+  /// statement is a yield* statement.
+  Statement createYieldStatement(int fileOffset, Expression expression,
+      {bool isYieldStar}) {
+    assert(fileOffset != null);
+    assert(isYieldStar != null);
+    return new YieldStatement(expression, isYieldStar: isYieldStar)
+      ..fileOffset = fileOffset;
   }
 
   bool isBlock(Object node) => node is Block;
 
-  /// Return `true` if the given [statement] is the representation of an empty
-  /// statement.
-  bool isEmptyStatement(Statement statement) => statement is EmptyStatement;
-
   bool isErroneousNode(Object node) {
     if (node is ExpressionStatement) {
       ExpressionStatement statement = node;
@@ -606,11 +552,6 @@
     return node is InvalidExpression;
   }
 
-  /// Return `true` if the given [statement] is the representation of an
-  /// expression statement.
-  bool isExpressionStatement(Statement statement) =>
-      statement is ExpressionStatement;
-
   bool isThisExpression(Object node) => node is ThisExpression;
 
   bool isVariablesDeclaration(Object node) => node is _VariablesDeclaration;
@@ -618,7 +559,7 @@
   /// Creates [VariableDeclaration] for a variable named [name] at the given
   /// [functionNestingLevel].
   VariableDeclaration createVariableDeclaration(
-      String name, int functionNestingLevel,
+      int fileOffset, String name, int functionNestingLevel,
       {Expression initializer,
       DartType type,
       bool isFinal: false,
@@ -626,6 +567,7 @@
       bool isFieldFormal: false,
       bool isCovariant: false,
       bool isLocalFunction: false}) {
+    assert(fileOffset != null);
     return new VariableDeclarationImpl(name, functionNestingLevel,
         type: type,
         initializer: initializer,
@@ -636,19 +578,18 @@
         isLocalFunction: isLocalFunction);
   }
 
-  VariableDeclaration createVariableDeclarationForValue(
-      int fileOffset, Expression initializer,
+  VariableDeclaration createVariableDeclarationForValue(Expression initializer,
       {DartType type = const DynamicType()}) {
     return new VariableDeclarationImpl.forValue(initializer)
       ..type = type
-      ..fileOffset = fileOffset ?? TreeNode.noOffset;
+      ..fileOffset = initializer.fileOffset;
   }
 
   Let createLet(VariableDeclaration variable, Expression body) {
     return new Let(variable, body);
   }
 
-  FunctionNode createFunctionNode(Statement body,
+  FunctionNode createFunctionNode(int fileOffset, Statement body,
       {List<TypeParameter> typeParameters,
       List<VariableDeclaration> positionalParameters,
       List<VariableDeclaration> namedParameters,
@@ -656,6 +597,7 @@
       DartType returnType: const DynamicType(),
       AsyncMarker asyncMarker: AsyncMarker.Sync,
       AsyncMarker dartAsyncMarker}) {
+    assert(fileOffset != null);
     return new FunctionNode(body,
         typeParameters: typeParameters,
         positionalParameters: positionalParameters,
@@ -676,48 +618,55 @@
 
   FunctionExpression createFunctionExpression(
       int fileOffset, FunctionNode function) {
-    return new FunctionExpression(function)
-      ..fileOffset = fileOffset ?? TreeNode.noOffset;
+    assert(fileOffset != null);
+    return new FunctionExpression(function)..fileOffset = fileOffset;
   }
 
   MethodInvocation createFunctionInvocation(
       int fileOffset, Expression expression, Arguments arguments) {
+    assert(fileOffset != null);
     return new MethodInvocationImpl(expression, callName, arguments)
-      ..fileOffset = fileOffset ?? TreeNode.noOffset;
+      ..fileOffset = fileOffset;
   }
 
   MethodInvocation createMethodInvocation(
       int fileOffset, Expression expression, Name name, Arguments arguments,
       {bool isImplicitCall: false, Member interfaceTarget}) {
+    assert(fileOffset != null);
     return new MethodInvocationImpl(expression, name, arguments,
         isImplicitCall: isImplicitCall)
-      ..fileOffset = fileOffset ?? TreeNode.noOffset
+      ..fileOffset = fileOffset
       ..interfaceTarget = interfaceTarget;
   }
 
-  NamedExpression createNamedExpression(String name, Expression expression) {
-    return new NamedExpression(name, expression);
+  NamedExpression createNamedExpression(
+      int fileOffset, String name, Expression expression) {
+    assert(fileOffset != null);
+    return new NamedExpression(name, expression)..fileOffset = fileOffset;
   }
 
   StaticInvocation createStaticInvocation(
       int fileOffset, Procedure procedure, Arguments arguments) {
-    return new StaticInvocation(procedure, arguments)
-      ..fileOffset = fileOffset ?? TreeNode.noOffset;
+    assert(fileOffset != null);
+    return new StaticInvocation(procedure, arguments)..fileOffset = fileOffset;
   }
 
   SuperMethodInvocation createSuperMethodInvocation(
       int fileOffset, Name name, Procedure procedure, Arguments arguments) {
+    assert(fileOffset != null);
     return new SuperMethodInvocation(name, arguments, procedure)
-      ..fileOffset = fileOffset ?? TreeNode.noOffset;
+      ..fileOffset = fileOffset;
   }
 
   NullCheck createNullCheck(int fileOffset, Expression expression) {
+    assert(fileOffset != null);
     return new NullCheck(expression)..fileOffset = fileOffset;
   }
 
   PropertySet createPropertySet(
       int fileOffset, Expression receiver, Name name, Expression value,
       {Member interfaceTarget, bool forEffect, bool readOnlyReceiver: false}) {
+    assert(fileOffset != null);
     return new PropertySetImpl(receiver, name, value,
         interfaceTarget: interfaceTarget,
         forEffect: forEffect,
diff --git a/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart b/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart
index 764d18b..3c9d8f2c 100644
--- a/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/forwarding_node.dart
@@ -29,6 +29,8 @@
 
 import "package:kernel/type_algebra.dart" show Substitution;
 
+import "../builder/class_builder.dart";
+
 import "../problems.dart" show unhandled;
 
 import "../type_inference/type_inference_engine.dart"
@@ -36,26 +38,25 @@
 
 import "../type_inference/type_inferrer.dart" show getNamedFormal;
 
-import "kernel_builder.dart"
-    show ClassHierarchyBuilder, Builder, DelayedMember, ClassBuilder;
+import 'class_hierarchy_builder.dart';
 
 class ForwardingNode {
   final ClassHierarchyBuilder hierarchy;
 
   final ClassBuilder parent;
 
-  final Builder combinedMemberSignatureResult;
+  final ClassMember combinedMemberSignatureResult;
 
   final ProcedureKind kind;
 
   /// A list containing the directly implemented and directly inherited
   /// procedures of the class in question.
-  final List<Builder> _candidates;
+  final List<ClassMember> _candidates;
 
   ForwardingNode(this.hierarchy, this.parent,
       this.combinedMemberSignatureResult, this._candidates, this.kind);
 
-  Name get name => combinedMemberSignatureResult.target.name;
+  Name get name => combinedMemberSignatureResult.member.name;
 
   Class get enclosingClass => parent.cls;
 
@@ -74,7 +75,7 @@
   /// they would not be checked in an inherited implementation, a forwarding
   /// stub is introduced as a place to put the checks.
   Member _computeCovarianceFixes() {
-    Member interfaceMember = combinedMemberSignatureResult.target;
+    Member interfaceMember = combinedMemberSignatureResult.member;
     Substitution substitution =
         _substitutionFor(interfaceMember, enclosingClass);
     // We always create a forwarding stub when we've inherited a member from an
@@ -355,9 +356,9 @@
 
   /// Returns the [i]th element of [_candidates], finalizing it if necessary.
   Member getCandidateAt(int i) {
-    Builder candidate = _candidates[i];
+    ClassMember candidate = _candidates[i];
     assert(candidate is! DelayedMember);
-    return candidate.target;
+    return candidate.member;
   }
 
   static Member _getForwardingStubSuperTarget(Procedure forwardingStub) {
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 6f1317a..0268710 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,9 +6,9 @@
 
 import 'package:kernel/ast.dart' show VariableDeclaration;
 
-import 'kernel_builder.dart' show Builder;
+import '../builder/declaration.dart';
 
-class VariableBuilder extends Builder {
+class VariableBuilder extends BuilderImpl {
   @override
   final Builder parent;
 
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 c22f4d5..e071810 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,12 +19,12 @@
 
 import '../source/source_library_builder.dart' show SourceLibraryBuilder;
 
-import 'kernel_builder.dart' show Builder;
+import '../builder/declaration.dart';
 
 import 'forest.dart' show Forest;
 
 /// Builder to represent the `deferLibrary.loadLibrary` calls and tear-offs.
-class LoadLibraryBuilder extends Builder {
+class LoadLibraryBuilder extends BuilderImpl {
   final SourceLibraryBuilder parent;
 
   final LibraryDependency importDependency;
@@ -42,8 +42,7 @@
 
   LoadLibrary createLoadLibrary(
       int charOffset, Forest forest, Arguments arguments) {
-    return forest.createLoadLibrary(importDependency, arguments)
-      ..fileOffset = charOffset;
+    return forest.createLoadLibrary(charOffset, importDependency, arguments);
   }
 
   Procedure createTearoffMethod(Forest forest) {
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 df16b06..edc3835 100644
--- a/pkg/front_end/lib/src/fasta/kernel/unlinked_scope.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/unlinked_scope.dart
@@ -2,6 +2,8 @@
 // for 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 'kernel_builder.dart' show Builder, Scope;
 
 /// Scope that returns an [UnlinkedDeclaration] if a name can't be resolved.
@@ -16,7 +18,7 @@
   }
 }
 
-class UnlinkedDeclaration extends Builder {
+class UnlinkedDeclaration extends BuilderImpl {
   final String name;
 
   final bool isInstanceScope;
diff --git a/pkg/front_end/lib/src/fasta/scope.dart b/pkg/front_end/lib/src/fasta/scope.dart
index 404a00e..8bb9bf9 100644
--- a/pkg/front_end/lib/src/fasta/scope.dart
+++ b/pkg/front_end/lib/src/fasta/scope.dart
@@ -4,7 +4,9 @@
 
 library fasta.scope;
 
-import 'builder/builder.dart' show Builder, NameIterator, TypeVariableBuilder;
+import 'builder/builder.dart' show NameIterator, TypeVariableBuilder;
+
+import 'builder/declaration.dart';
 
 import 'builder/extension_builder.dart';
 
@@ -410,7 +412,7 @@
   Builder operator [](String name) => scope.local[name];
 }
 
-abstract class ProblemBuilder extends Builder {
+abstract class ProblemBuilder extends BuilderImpl {
   final String name;
 
   final Builder builder;
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 6499fc8..0800b4b 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,6 +7,8 @@
 import 'package:kernel/ast.dart'
     show Class, Constructor, Member, Supertype, TreeNode;
 
+import '../builder/class_builder.dart';
+
 import '../dill/dill_member_builder.dart' show DillMemberBuilder;
 
 import '../fasta_codes.dart'
@@ -24,7 +26,6 @@
 
 import '../kernel/kernel_builder.dart'
     show
-        ClassBuilder,
         ConstructorReferenceBuilder,
         Builder,
         FieldBuilder,
@@ -71,7 +72,7 @@
   return cls;
 }
 
-class SourceClassBuilder extends ClassBuilder
+class SourceClassBuilder extends ClassBuilderImpl
     implements Comparable<SourceClassBuilder> {
   @override
   final Class actualCls;
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 09ac319..36ca7a8 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
@@ -27,7 +27,7 @@
         templateExtensionMemberConflictsWithObjectMember;
 import 'source_library_builder.dart';
 
-class SourceExtensionBuilder extends ExtensionBuilder {
+class SourceExtensionBuilder extends ExtensionBuilderImpl {
   final Extension _extension;
 
   SourceExtensionBuilder _origin;
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 c1fcc30..00f980e 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
@@ -60,13 +60,12 @@
 
 import '../builder/builder.dart'
     show
+        Builder,
         ClassBuilder,
         ConstructorReferenceBuilder,
-        Builder,
         EnumConstantInfo,
         FormalParameterBuilder,
         FunctionTypeBuilder,
-        LibraryBuilder,
         MemberBuilder,
         MetadataBuilder,
         NameIterator,
@@ -83,6 +82,8 @@
 
 import '../builder/extension_builder.dart';
 
+import '../builder/library_builder.dart';
+
 import '../combinator.dart' show Combinator;
 
 import '../configuration.dart' show Configuration;
@@ -228,7 +229,7 @@
 
 import 'source_loader.dart' show SourceLoader;
 
-class SourceLibraryBuilder extends LibraryBuilder {
+class SourceLibraryBuilder extends LibraryBuilderImpl {
   static const String MALFORMED_URI_SCHEME = "org-dartlang-malformed-uri";
 
   final SourceLoader loader;
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 cd2c0bf..bc077b2 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -912,7 +912,7 @@
     Set<Class> changedClasses = new Set<Class>();
     for (int i = 0; i < delayedMemberChecks.length; i++) {
       delayedMemberChecks[i].check(builderHierarchy);
-      changedClasses.add(delayedMemberChecks[i].parent.cls);
+      changedClasses.add(delayedMemberChecks[i].classBuilder.cls);
     }
     ticker.logMs(
         "Computed ${delayedMemberChecks.length} combined member signatures");
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 67cdaec..ad16fe4 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/builder.dart' show Builder;
+import '../builder/declaration.dart';
 
 import '../messages.dart' show LocatedMessage, Message, MessageCode;
 
@@ -98,7 +98,7 @@
   void checkEmpty(Token token) {}
 }
 
-class UnspecifiedDeclaration extends Builder {
+class UnspecifiedDeclaration extends BuilderImpl {
   final String name;
 
   @override
@@ -119,7 +119,7 @@
   String toString() => "UnspecifiedDeclaration($name)";
 }
 
-class NoArguments extends Builder {
+class NoArguments extends BuilderImpl {
   NoArguments();
 
   @override
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 2047483..aff85ed 100644
--- a/pkg/front_end/lib/src/fasta/source/value_kinds.dart
+++ b/pkg/front_end/lib/src/fasta/source/value_kinds.dart
@@ -37,6 +37,8 @@
   static const ValueKind ArgumentsOrNull =
       const _SingleValueKind<type.Arguments>(NullValue.Arguments);
   static const ValueKind Expression = const _SingleValueKind<type.Expression>();
+  static const ValueKind ExpressionOrNull =
+      const _SingleValueKind<type.Expression>(NullValue.Expression);
   static const ValueKind Identifier = const _SingleValueKind<type.Identifier>();
   static const ValueKind IdentifierOrNull =
       const _SingleValueKind<type.Identifier>(NullValue.Identifier);
@@ -65,6 +67,7 @@
       const _UnionValueKind([Name, ParserRecovery]);
   static const ValueKind MetadataListOrNull =
       const _SingleValueKind<List<type.MetadataBuilder>>(NullValue.Metadata);
+  static const ValueKind ObjectList = const _SingleValueKind<List<Object>>();
   static const ValueKind Operator = const _SingleValueKind<type.Operator>();
   static const ValueKind ParserRecovery =
       const _SingleValueKind<type.ParserRecovery>();
@@ -72,6 +75,7 @@
       const _SingleValueKind<type.ProblemBuilder>();
   static const ValueKind QualifiedName =
       const _SingleValueKind<type.QualifiedName>();
+  static const ValueKind Statement = const _SingleValueKind<type.Statement>();
   static const ValueKind Token = const _SingleValueKind<type.Token>();
   static const ValueKind TokenOrNull =
       const _SingleValueKind<type.Token>(NullValue.Token);
diff --git a/pkg/front_end/parser_testcases/extensions/covariant.dart b/pkg/front_end/parser_testcases/extensions/covariant.dart
new file mode 100644
index 0000000..425eb67
--- /dev/null
+++ b/pkg/front_end/parser_testcases/extensions/covariant.dart
@@ -0,0 +1,7 @@
+class A {}
+
+class C extends A {}
+
+extension on C {
+  addChild(covariant A child) {}
+}
diff --git a/pkg/front_end/parser_testcases/extensions/covariant.dart.expect b/pkg/front_end/parser_testcases/extensions/covariant.dart.expect
new file mode 100644
index 0000000..ebb1635
--- /dev/null
+++ b/pkg/front_end/parser_testcases/extensions/covariant.dart.expect
@@ -0,0 +1,70 @@
+beginCompilationUnit(class)
+  beginMetadataStar(class)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(class)
+    handleIdentifier(A, classOrMixinDeclaration)
+    handleNoTypeVariables({)
+    beginClassDeclaration(class, null, A)
+      handleNoType(A)
+      handleClassExtends(null)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(class, class, null)
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+      endClassOrMixinBody(DeclarationKind.Class, 0, {, })
+    endClassDeclaration(class, })
+  endTopLevelDeclaration(class)
+  beginMetadataStar(class)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(class)
+    handleIdentifier(C, classOrMixinDeclaration)
+    handleNoTypeVariables(extends)
+    beginClassDeclaration(class, null, C)
+      handleIdentifier(A, typeReference)
+      handleNoTypeArguments({)
+      handleType(A, null)
+      handleClassExtends(extends)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(class, class, null)
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+      endClassOrMixinBody(DeclarationKind.Class, 0, {, })
+    endClassDeclaration(class, })
+  endTopLevelDeclaration(extension)
+  beginMetadataStar(extension)
+  endMetadataStar(0)
+  beginExtensionDeclarationPrelude(extension)
+    handleNoTypeVariables(on)
+    beginExtensionDeclaration(extension, null)
+      handleIdentifier(C, typeReference)
+      handleNoTypeArguments({)
+      handleType(C, null)
+      beginClassOrMixinBody(DeclarationKind.Extension, {)
+        beginMetadataStar(addChild)
+        endMetadataStar(0)
+        beginMember()
+          beginMethod(null, null, null, null, null, addChild)
+            handleNoType({)
+            handleIdentifier(addChild, methodDeclaration)
+            handleNoTypeVariables(()
+            beginFormalParameters((, MemberKind.NonStaticMethod)
+              beginMetadataStar(covariant)
+              endMetadataStar(0)
+              beginFormalParameter(covariant, MemberKind.NonStaticMethod, null, covariant, 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)
+            handleNoInitializers()
+            handleAsyncModifier(null, null)
+            beginBlockFunctionBody({)
+            endBlockFunctionBody(0, {, })
+          endExtensionMethod(null, addChild, (, null, })
+        endMember()
+      endClassOrMixinBody(DeclarationKind.Extension, 1, {, })
+    endExtensionDeclaration(extension, on, })
+  endTopLevelDeclaration()
+endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/extensions/covariant.dart.intertwined.expect b/pkg/front_end/parser_testcases/extensions/covariant.dart.intertwined.expect
new file mode 100644
index 0000000..6cf377f
--- /dev/null
+++ b/pkg/front_end/parser_testcases/extensions/covariant.dart.intertwined.expect
@@ -0,0 +1,126 @@
+parseUnit(class)
+  skipErrorTokens(class)
+  listener: beginCompilationUnit(class)
+  syntheticPreviousToken(class)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(class)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(, class, Instance of 'DirectiveContext')
+      parseClassDeclarationModifiers(, class)
+      parseClassOrNamedMixinApplication(null, class)
+        listener: beginClassOrNamedMixinApplicationPrelude(class)
+        ensureIdentifier(class, classOrMixinDeclaration)
+          listener: handleIdentifier(A, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, A)
+        parseClass(A, class, class, A)
+          parseClassHeaderOpt(A, class, class)
+            parseClassExtendsOpt(A)
+              listener: handleNoType(A)
+              listener: handleClassExtends(null)
+            parseWithClauseOpt(A)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(A)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(A, DeclarationKind.Class, A)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 0, {, })
+          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(C, classOrMixinDeclaration)
+        listener: handleNoTypeVariables(extends)
+        listener: beginClassDeclaration(class, null, C)
+        parseClass(C, class, class, C)
+          parseClassHeaderOpt(C, class, class)
+            parseClassExtendsOpt(C)
+              listener: handleIdentifier(A, typeReference)
+              listener: handleNoTypeArguments({)
+              listener: handleType(A, null)
+              listener: handleClassExtends(extends)
+            parseWithClauseOpt(A)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(A)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(A, DeclarationKind.Class, C)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 0, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration(extension)
+  parseTopLevelDeclarationImpl(}, Instance of 'DirectiveContext')
+    parseMetadataStar(})
+      listener: beginMetadataStar(extension)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(}, extension, Instance of 'DirectiveContext')
+      parseTopLevelKeywordModifiers(}, extension)
+      parseExtension(extension)
+        listener: beginExtensionDeclarationPrelude(extension)
+        listener: handleNoTypeVariables(on)
+        listener: beginExtensionDeclaration(extension, null)
+        listener: handleIdentifier(C, typeReference)
+        listener: handleNoTypeArguments({)
+        listener: handleType(C, null)
+        parseClassOrMixinOrExtensionBody(C, DeclarationKind.Extension, null)
+          listener: beginClassOrMixinBody(DeclarationKind.Extension, {)
+          notEofOrValue(}, addChild)
+          parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Extension, null)
+            parseMetadataStar({)
+              listener: beginMetadataStar(addChild)
+              listener: endMetadataStar(0)
+            listener: beginMember()
+            parseMethod({, null, null, null, null, null, {, Instance of 'NoType', null, addChild, DeclarationKind.Extension, null)
+              listener: beginMethod(null, null, null, null, null, addChild)
+              listener: handleNoType({)
+              ensureIdentifier({, methodDeclaration)
+                listener: handleIdentifier(addChild, methodDeclaration)
+              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)
+                      parseMetadataStar(()
+                        listener: beginMetadataStar(covariant)
+                        listener: endMetadataStar(0)
+                      listener: beginFormalParameter(covariant, MemberKind.NonStaticMethod, null, covariant, 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)
+              parseInitializersOpt())
+                listener: handleNoInitializers()
+              parseAsyncModifierOpt())
+                listener: handleAsyncModifier(null, null)
+                inPlainSync()
+              inPlainSync()
+              parseFunctionBody(), false, true)
+                listener: beginBlockFunctionBody({)
+                notEofOrValue(}, })
+                listener: endBlockFunctionBody(0, {, })
+              listener: endExtensionMethod(null, addChild, (, null, })
+            listener: endMember()
+          notEofOrValue(}, })
+          listener: endClassOrMixinBody(DeclarationKind.Extension, 1, {, })
+        listener: endExtensionDeclaration(extension, on, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(class)
+  listener: endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/extensions/not_covariant.dart b/pkg/front_end/parser_testcases/extensions/not_covariant.dart
new file mode 100644
index 0000000..0b9adf3
--- /dev/null
+++ b/pkg/front_end/parser_testcases/extensions/not_covariant.dart
@@ -0,0 +1,7 @@
+class A {}
+
+class C extends A {}
+
+extension on C {
+  addChild(A child) {}
+}
diff --git a/pkg/front_end/parser_testcases/extensions/not_covariant.dart.expect b/pkg/front_end/parser_testcases/extensions/not_covariant.dart.expect
new file mode 100644
index 0000000..b0b1098
--- /dev/null
+++ b/pkg/front_end/parser_testcases/extensions/not_covariant.dart.expect
@@ -0,0 +1,70 @@
+beginCompilationUnit(class)
+  beginMetadataStar(class)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(class)
+    handleIdentifier(A, classOrMixinDeclaration)
+    handleNoTypeVariables({)
+    beginClassDeclaration(class, null, A)
+      handleNoType(A)
+      handleClassExtends(null)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(class, class, null)
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+      endClassOrMixinBody(DeclarationKind.Class, 0, {, })
+    endClassDeclaration(class, })
+  endTopLevelDeclaration(class)
+  beginMetadataStar(class)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(class)
+    handleIdentifier(C, classOrMixinDeclaration)
+    handleNoTypeVariables(extends)
+    beginClassDeclaration(class, null, C)
+      handleIdentifier(A, typeReference)
+      handleNoTypeArguments({)
+      handleType(A, null)
+      handleClassExtends(extends)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(class, class, null)
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+      endClassOrMixinBody(DeclarationKind.Class, 0, {, })
+    endClassDeclaration(class, })
+  endTopLevelDeclaration(extension)
+  beginMetadataStar(extension)
+  endMetadataStar(0)
+  beginExtensionDeclarationPrelude(extension)
+    handleNoTypeVariables(on)
+    beginExtensionDeclaration(extension, null)
+      handleIdentifier(C, typeReference)
+      handleNoTypeArguments({)
+      handleType(C, null)
+      beginClassOrMixinBody(DeclarationKind.Extension, {)
+        beginMetadataStar(addChild)
+        endMetadataStar(0)
+        beginMember()
+          beginMethod(null, null, null, null, null, addChild)
+            handleNoType({)
+            handleIdentifier(addChild, methodDeclaration)
+            handleNoTypeVariables(()
+            beginFormalParameters((, MemberKind.NonStaticMethod)
+              beginMetadataStar(A)
+              endMetadataStar(0)
+              beginFormalParameter(A, MemberKind.NonStaticMethod, 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)
+            handleNoInitializers()
+            handleAsyncModifier(null, null)
+            beginBlockFunctionBody({)
+            endBlockFunctionBody(0, {, })
+          endExtensionMethod(null, addChild, (, null, })
+        endMember()
+      endClassOrMixinBody(DeclarationKind.Extension, 1, {, })
+    endExtensionDeclaration(extension, on, })
+  endTopLevelDeclaration()
+endCompilationUnit(3, )
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
new file mode 100644
index 0000000..18aa1ae
--- /dev/null
+++ b/pkg/front_end/parser_testcases/extensions/not_covariant.dart.intertwined.expect
@@ -0,0 +1,126 @@
+parseUnit(class)
+  skipErrorTokens(class)
+  listener: beginCompilationUnit(class)
+  syntheticPreviousToken(class)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(class)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(, class, Instance of 'DirectiveContext')
+      parseClassDeclarationModifiers(, class)
+      parseClassOrNamedMixinApplication(null, class)
+        listener: beginClassOrNamedMixinApplicationPrelude(class)
+        ensureIdentifier(class, classOrMixinDeclaration)
+          listener: handleIdentifier(A, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, A)
+        parseClass(A, class, class, A)
+          parseClassHeaderOpt(A, class, class)
+            parseClassExtendsOpt(A)
+              listener: handleNoType(A)
+              listener: handleClassExtends(null)
+            parseWithClauseOpt(A)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(A)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(A, DeclarationKind.Class, A)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 0, {, })
+          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(C, classOrMixinDeclaration)
+        listener: handleNoTypeVariables(extends)
+        listener: beginClassDeclaration(class, null, C)
+        parseClass(C, class, class, C)
+          parseClassHeaderOpt(C, class, class)
+            parseClassExtendsOpt(C)
+              listener: handleIdentifier(A, typeReference)
+              listener: handleNoTypeArguments({)
+              listener: handleType(A, null)
+              listener: handleClassExtends(extends)
+            parseWithClauseOpt(A)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(A)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(A, DeclarationKind.Class, C)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 0, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration(extension)
+  parseTopLevelDeclarationImpl(}, Instance of 'DirectiveContext')
+    parseMetadataStar(})
+      listener: beginMetadataStar(extension)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(}, extension, Instance of 'DirectiveContext')
+      parseTopLevelKeywordModifiers(}, extension)
+      parseExtension(extension)
+        listener: beginExtensionDeclarationPrelude(extension)
+        listener: handleNoTypeVariables(on)
+        listener: beginExtensionDeclaration(extension, null)
+        listener: handleIdentifier(C, typeReference)
+        listener: handleNoTypeArguments({)
+        listener: handleType(C, null)
+        parseClassOrMixinOrExtensionBody(C, DeclarationKind.Extension, null)
+          listener: beginClassOrMixinBody(DeclarationKind.Extension, {)
+          notEofOrValue(}, addChild)
+          parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Extension, null)
+            parseMetadataStar({)
+              listener: beginMetadataStar(addChild)
+              listener: endMetadataStar(0)
+            listener: beginMember()
+            parseMethod({, null, null, null, null, null, {, Instance of 'NoType', null, addChild, DeclarationKind.Extension, null)
+              listener: beginMethod(null, null, null, null, null, addChild)
+              listener: handleNoType({)
+              ensureIdentifier({, methodDeclaration)
+                listener: handleIdentifier(addChild, methodDeclaration)
+              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)
+                      parseMetadataStar(()
+                        listener: beginMetadataStar(A)
+                        listener: endMetadataStar(0)
+                      listener: beginFormalParameter(A, MemberKind.NonStaticMethod, 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)
+              parseInitializersOpt())
+                listener: handleNoInitializers()
+              parseAsyncModifierOpt())
+                listener: handleAsyncModifier(null, null)
+                inPlainSync()
+              inPlainSync()
+              parseFunctionBody(), false, true)
+                listener: beginBlockFunctionBody({)
+                notEofOrValue(}, })
+                listener: endBlockFunctionBody(0, {, })
+              listener: endExtensionMethod(null, addChild, (, null, })
+            listener: endMember()
+          notEofOrValue(}, })
+          listener: endClassOrMixinBody(DeclarationKind.Extension, 1, {, })
+        listener: endExtensionDeclaration(extension, on, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(class)
+  listener: endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/extensions/static.dart b/pkg/front_end/parser_testcases/extensions/static.dart
new file mode 100644
index 0000000..e1a2a79
--- /dev/null
+++ b/pkg/front_end/parser_testcases/extensions/static.dart
@@ -0,0 +1,7 @@
+class A {}
+
+class C extends A {}
+
+extension on C {
+  static addChild(A child) {}
+}
diff --git a/pkg/front_end/parser_testcases/extensions/static.dart.expect b/pkg/front_end/parser_testcases/extensions/static.dart.expect
new file mode 100644
index 0000000..7b1a576
--- /dev/null
+++ b/pkg/front_end/parser_testcases/extensions/static.dart.expect
@@ -0,0 +1,70 @@
+beginCompilationUnit(class)
+  beginMetadataStar(class)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(class)
+    handleIdentifier(A, classOrMixinDeclaration)
+    handleNoTypeVariables({)
+    beginClassDeclaration(class, null, A)
+      handleNoType(A)
+      handleClassExtends(null)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(class, class, null)
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+      endClassOrMixinBody(DeclarationKind.Class, 0, {, })
+    endClassDeclaration(class, })
+  endTopLevelDeclaration(class)
+  beginMetadataStar(class)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(class)
+    handleIdentifier(C, classOrMixinDeclaration)
+    handleNoTypeVariables(extends)
+    beginClassDeclaration(class, null, C)
+      handleIdentifier(A, typeReference)
+      handleNoTypeArguments({)
+      handleType(A, null)
+      handleClassExtends(extends)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(class, class, null)
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+      endClassOrMixinBody(DeclarationKind.Class, 0, {, })
+    endClassDeclaration(class, })
+  endTopLevelDeclaration(extension)
+  beginMetadataStar(extension)
+  endMetadataStar(0)
+  beginExtensionDeclarationPrelude(extension)
+    handleNoTypeVariables(on)
+    beginExtensionDeclaration(extension, null)
+      handleIdentifier(C, typeReference)
+      handleNoTypeArguments({)
+      handleType(C, null)
+      beginClassOrMixinBody(DeclarationKind.Extension, {)
+        beginMetadataStar(static)
+        endMetadataStar(0)
+        beginMember()
+          beginMethod(null, static, null, null, null, addChild)
+            handleNoType(static)
+            handleIdentifier(addChild, methodDeclaration)
+            handleNoTypeVariables(()
+            beginFormalParameters((, MemberKind.StaticMethod)
+              beginMetadataStar(A)
+              endMetadataStar(0)
+              beginFormalParameter(A, MemberKind.StaticMethod, 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)
+            handleNoInitializers()
+            handleAsyncModifier(null, null)
+            beginBlockFunctionBody({)
+            endBlockFunctionBody(0, {, })
+          endExtensionMethod(null, static, (, null, })
+        endMember()
+      endClassOrMixinBody(DeclarationKind.Extension, 1, {, })
+    endExtensionDeclaration(extension, on, })
+  endTopLevelDeclaration()
+endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/extensions/static.dart.intertwined.expect b/pkg/front_end/parser_testcases/extensions/static.dart.intertwined.expect
new file mode 100644
index 0000000..6db427e
--- /dev/null
+++ b/pkg/front_end/parser_testcases/extensions/static.dart.intertwined.expect
@@ -0,0 +1,125 @@
+parseUnit(class)
+  skipErrorTokens(class)
+  listener: beginCompilationUnit(class)
+  syntheticPreviousToken(class)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(class)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(, class, Instance of 'DirectiveContext')
+      parseClassDeclarationModifiers(, class)
+      parseClassOrNamedMixinApplication(null, class)
+        listener: beginClassOrNamedMixinApplicationPrelude(class)
+        ensureIdentifier(class, classOrMixinDeclaration)
+          listener: handleIdentifier(A, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, A)
+        parseClass(A, class, class, A)
+          parseClassHeaderOpt(A, class, class)
+            parseClassExtendsOpt(A)
+              listener: handleNoType(A)
+              listener: handleClassExtends(null)
+            parseWithClauseOpt(A)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(A)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(A, DeclarationKind.Class, A)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 0, {, })
+          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(C, classOrMixinDeclaration)
+        listener: handleNoTypeVariables(extends)
+        listener: beginClassDeclaration(class, null, C)
+        parseClass(C, class, class, C)
+          parseClassHeaderOpt(C, class, class)
+            parseClassExtendsOpt(C)
+              listener: handleIdentifier(A, typeReference)
+              listener: handleNoTypeArguments({)
+              listener: handleType(A, null)
+              listener: handleClassExtends(extends)
+            parseWithClauseOpt(A)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(A)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(A, DeclarationKind.Class, C)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 0, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration(extension)
+  parseTopLevelDeclarationImpl(}, Instance of 'DirectiveContext')
+    parseMetadataStar(})
+      listener: beginMetadataStar(extension)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(}, extension, Instance of 'DirectiveContext')
+      parseTopLevelKeywordModifiers(}, extension)
+      parseExtension(extension)
+        listener: beginExtensionDeclarationPrelude(extension)
+        listener: handleNoTypeVariables(on)
+        listener: beginExtensionDeclaration(extension, null)
+        listener: handleIdentifier(C, typeReference)
+        listener: handleNoTypeArguments({)
+        listener: handleType(C, null)
+        parseClassOrMixinOrExtensionBody(C, DeclarationKind.Extension, null)
+          listener: beginClassOrMixinBody(DeclarationKind.Extension, {)
+          notEofOrValue(}, static)
+          parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Extension, null)
+            parseMetadataStar({)
+              listener: beginMetadataStar(static)
+              listener: endMetadataStar(0)
+            listener: beginMember()
+            parseMethod({, null, static, null, null, null, static, Instance of 'NoType', null, addChild, DeclarationKind.Extension, null)
+              listener: beginMethod(null, static, null, null, null, addChild)
+              listener: handleNoType(static)
+              ensureIdentifier(static, methodDeclaration)
+                listener: handleIdentifier(addChild, methodDeclaration)
+              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)
+                      parseMetadataStar(()
+                        listener: beginMetadataStar(A)
+                        listener: endMetadataStar(0)
+                      listener: beginFormalParameter(A, MemberKind.StaticMethod, 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)
+              parseInitializersOpt())
+                listener: handleNoInitializers()
+              parseAsyncModifierOpt())
+                listener: handleAsyncModifier(null, null)
+                inPlainSync()
+              parseFunctionBody(), false, false)
+                listener: beginBlockFunctionBody({)
+                notEofOrValue(}, })
+                listener: endBlockFunctionBody(0, {, })
+              listener: endExtensionMethod(null, static, (, null, })
+            listener: endMember()
+          notEofOrValue(}, })
+          listener: endClassOrMixinBody(DeclarationKind.Extension, 1, {, })
+        listener: endExtensionDeclaration(extension, on, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(class)
+  listener: endCompilationUnit(3, )
diff --git a/pkg/front_end/parser_testcases/extensions/static_covariant.dart b/pkg/front_end/parser_testcases/extensions/static_covariant.dart
new file mode 100644
index 0000000..8d855dc
--- /dev/null
+++ b/pkg/front_end/parser_testcases/extensions/static_covariant.dart
@@ -0,0 +1,7 @@
+class A {}
+
+class C extends A {}
+
+extension on C {
+  static addChild(covariant A child) {}
+}
diff --git a/pkg/front_end/parser_testcases/extensions/static_covariant.dart.expect b/pkg/front_end/parser_testcases/extensions/static_covariant.dart.expect
new file mode 100644
index 0000000..f953361
--- /dev/null
+++ b/pkg/front_end/parser_testcases/extensions/static_covariant.dart.expect
@@ -0,0 +1,71 @@
+beginCompilationUnit(class)
+  beginMetadataStar(class)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(class)
+    handleIdentifier(A, classOrMixinDeclaration)
+    handleNoTypeVariables({)
+    beginClassDeclaration(class, null, A)
+      handleNoType(A)
+      handleClassExtends(null)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(class, class, null)
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+      endClassOrMixinBody(DeclarationKind.Class, 0, {, })
+    endClassDeclaration(class, })
+  endTopLevelDeclaration(class)
+  beginMetadataStar(class)
+  endMetadataStar(0)
+  beginClassOrNamedMixinApplicationPrelude(class)
+    handleIdentifier(C, classOrMixinDeclaration)
+    handleNoTypeVariables(extends)
+    beginClassDeclaration(class, null, C)
+      handleIdentifier(A, typeReference)
+      handleNoTypeArguments({)
+      handleType(A, null)
+      handleClassExtends(extends)
+      handleClassNoWithClause()
+      handleClassOrMixinImplements(null, 0)
+      handleClassHeader(class, class, null)
+      beginClassOrMixinBody(DeclarationKind.Class, {)
+      endClassOrMixinBody(DeclarationKind.Class, 0, {, })
+    endClassDeclaration(class, })
+  endTopLevelDeclaration(extension)
+  beginMetadataStar(extension)
+  endMetadataStar(0)
+  beginExtensionDeclarationPrelude(extension)
+    handleNoTypeVariables(on)
+    beginExtensionDeclaration(extension, null)
+      handleIdentifier(C, typeReference)
+      handleNoTypeArguments({)
+      handleType(C, null)
+      beginClassOrMixinBody(DeclarationKind.Extension, {)
+        beginMetadataStar(static)
+        endMetadataStar(0)
+        beginMember()
+          beginMethod(null, static, null, null, null, addChild)
+            handleNoType(static)
+            handleIdentifier(addChild, methodDeclaration)
+            handleNoTypeVariables(()
+            beginFormalParameters((, MemberKind.StaticMethod)
+              beginMetadataStar(covariant)
+              endMetadataStar(0)
+              handleRecoverableError(Instance of 'Message', covariant, covariant)
+              beginFormalParameter(covariant, MemberKind.StaticMethod, 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)
+            handleNoInitializers()
+            handleAsyncModifier(null, null)
+            beginBlockFunctionBody({)
+            endBlockFunctionBody(0, {, })
+          endExtensionMethod(null, static, (, null, })
+        endMember()
+      endClassOrMixinBody(DeclarationKind.Extension, 1, {, })
+    endExtensionDeclaration(extension, on, })
+  endTopLevelDeclaration()
+endCompilationUnit(3, )
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
new file mode 100644
index 0000000..43cdc41
--- /dev/null
+++ b/pkg/front_end/parser_testcases/extensions/static_covariant.dart.intertwined.expect
@@ -0,0 +1,127 @@
+parseUnit(class)
+  skipErrorTokens(class)
+  listener: beginCompilationUnit(class)
+  syntheticPreviousToken(class)
+  parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext')
+    parseMetadataStar()
+      listener: beginMetadataStar(class)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(, class, Instance of 'DirectiveContext')
+      parseClassDeclarationModifiers(, class)
+      parseClassOrNamedMixinApplication(null, class)
+        listener: beginClassOrNamedMixinApplicationPrelude(class)
+        ensureIdentifier(class, classOrMixinDeclaration)
+          listener: handleIdentifier(A, classOrMixinDeclaration)
+        listener: handleNoTypeVariables({)
+        listener: beginClassDeclaration(class, null, A)
+        parseClass(A, class, class, A)
+          parseClassHeaderOpt(A, class, class)
+            parseClassExtendsOpt(A)
+              listener: handleNoType(A)
+              listener: handleClassExtends(null)
+            parseWithClauseOpt(A)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(A)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(A, DeclarationKind.Class, A)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 0, {, })
+          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(C, classOrMixinDeclaration)
+        listener: handleNoTypeVariables(extends)
+        listener: beginClassDeclaration(class, null, C)
+        parseClass(C, class, class, C)
+          parseClassHeaderOpt(C, class, class)
+            parseClassExtendsOpt(C)
+              listener: handleIdentifier(A, typeReference)
+              listener: handleNoTypeArguments({)
+              listener: handleType(A, null)
+              listener: handleClassExtends(extends)
+            parseWithClauseOpt(A)
+              listener: handleClassNoWithClause()
+            parseClassOrMixinImplementsOpt(A)
+              listener: handleClassOrMixinImplements(null, 0)
+            listener: handleClassHeader(class, class, null)
+          parseClassOrMixinOrExtensionBody(A, DeclarationKind.Class, C)
+            listener: beginClassOrMixinBody(DeclarationKind.Class, {)
+            notEofOrValue(}, })
+            listener: endClassOrMixinBody(DeclarationKind.Class, 0, {, })
+          listener: endClassDeclaration(class, })
+  listener: endTopLevelDeclaration(extension)
+  parseTopLevelDeclarationImpl(}, Instance of 'DirectiveContext')
+    parseMetadataStar(})
+      listener: beginMetadataStar(extension)
+      listener: endMetadataStar(0)
+    parseTopLevelKeywordDeclaration(}, extension, Instance of 'DirectiveContext')
+      parseTopLevelKeywordModifiers(}, extension)
+      parseExtension(extension)
+        listener: beginExtensionDeclarationPrelude(extension)
+        listener: handleNoTypeVariables(on)
+        listener: beginExtensionDeclaration(extension, null)
+        listener: handleIdentifier(C, typeReference)
+        listener: handleNoTypeArguments({)
+        listener: handleType(C, null)
+        parseClassOrMixinOrExtensionBody(C, DeclarationKind.Extension, null)
+          listener: beginClassOrMixinBody(DeclarationKind.Extension, {)
+          notEofOrValue(}, static)
+          parseClassOrMixinOrExtensionMemberImpl({, DeclarationKind.Extension, null)
+            parseMetadataStar({)
+              listener: beginMetadataStar(static)
+              listener: endMetadataStar(0)
+            listener: beginMember()
+            parseMethod({, null, static, null, null, null, static, Instance of 'NoType', null, addChild, DeclarationKind.Extension, null)
+              listener: beginMethod(null, static, null, null, null, addChild)
+              listener: handleNoType(static)
+              ensureIdentifier(static, methodDeclaration)
+                listener: handleIdentifier(addChild, methodDeclaration)
+              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)
+                      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: 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)
+              parseInitializersOpt())
+                listener: handleNoInitializers()
+              parseAsyncModifierOpt())
+                listener: handleAsyncModifier(null, null)
+                inPlainSync()
+              parseFunctionBody(), false, false)
+                listener: beginBlockFunctionBody({)
+                notEofOrValue(}, })
+                listener: endBlockFunctionBody(0, {, })
+              listener: endExtensionMethod(null, static, (, null, })
+            listener: endMember()
+          notEofOrValue(}, })
+          listener: endClassOrMixinBody(DeclarationKind.Extension, 1, {, })
+        listener: endExtensionDeclaration(extension, on, })
+  listener: endTopLevelDeclaration()
+  reportAllErrorTokens(class)
+  listener: endCompilationUnit(3, )
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 398f5a1..e707a31 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/builder.dart' show Builder;
+import 'package:front_end/src/fasta/builder/declaration.dart';
 
 import 'package:front_end/src/fasta/compiler_context.dart' show CompilerContext;
 
@@ -187,7 +187,7 @@
   }
 }
 
-class DebugDeclaration extends Builder {
+class DebugDeclaration extends BuilderImpl {
   final String name;
 
   @override
diff --git a/pkg/front_end/test/lint_test.status b/pkg/front_end/test/lint_test.status
index f943795..7f83b59 100644
--- a/pkg/front_end/test/lint_test.status
+++ b/pkg/front_end/test/lint_test.status
@@ -5,7 +5,6 @@
 src/api_unstable/bazel_worker/ImportsTwice: Fail
 src/fasta/builder/class_builder/ImportsTwice: Fail
 src/fasta/builder/field_builder/ImportsTwice: Fail
-src/fasta/builder/prefix_builder/ImportsTwice: Fail
 src/fasta/incremental_compiler/ImportsTwice: Fail
 src/fasta/kernel/body_builder/ImportsTwice: Fail
 src/fasta/kernel/expression_generator_helper/ImportsTwice: Fail
diff --git a/pkg/front_end/test/parser_test.dart b/pkg/front_end/test/parser_test.dart
index 9daee4d..10afc18 100644
--- a/pkg/front_end/test/parser_test.dart
+++ b/pkg/front_end/test/parser_test.dart
@@ -11,6 +11,7 @@
 import 'dart:typed_data' show Uint8List;
 
 import 'package:front_end/src/fasta/parser.dart' show Parser;
+import 'package:front_end/src/fasta/scanner.dart';
 
 import 'package:front_end/src/fasta/scanner/utf8_bytes_scanner.dart'
     show Utf8BytesScanner;
@@ -54,6 +55,11 @@
   return new Context(environment["updateExpectations"] == "true");
 }
 
+ScannerConfiguration scannerConfiguration = new ScannerConfiguration(
+    enableTripleShift: true,
+    enableExtensionMethods: true,
+    enableNonNullable: true);
+
 class Context extends ChainContext with MatchContext {
   final updateExpectations;
 
@@ -81,8 +87,8 @@
     Uint8List bytes = new Uint8List(rawBytes.length + 1);
     bytes.setRange(0, rawBytes.length, rawBytes);
 
-    Utf8BytesScanner scanner =
-        new Utf8BytesScanner(bytes, includeComments: true);
+    Utf8BytesScanner scanner = new Utf8BytesScanner(bytes,
+        includeComments: true, configuration: scannerConfiguration);
     Token firstToken = scanner.tokenize();
 
     if (firstToken == null) {
@@ -111,8 +117,8 @@
     Uint8List bytes = new Uint8List(rawBytes.length + 1);
     bytes.setRange(0, rawBytes.length, rawBytes);
 
-    Utf8BytesScanner scanner =
-        new Utf8BytesScanner(bytes, includeComments: true);
+    Utf8BytesScanner scanner = new Utf8BytesScanner(bytes,
+        includeComments: true, configuration: scannerConfiguration);
     Token firstToken = scanner.tokenize();
 
     if (firstToken == null) {
diff --git a/pkg/front_end/test/spell_checking_list_common.txt b/pkg/front_end/test/spell_checking_list_common.txt
index 493e5cd..1ab6594 100644
--- a/pkg/front_end/test/spell_checking_list_common.txt
+++ b/pkg/front_end/test/spell_checking_list_common.txt
@@ -103,6 +103,7 @@
 always
 ambiguous
 among
+amongst
 amount
 ampersand
 an
diff --git a/pkg/front_end/testcases/inference/infer_assign_to_implicit_this.dart b/pkg/front_end/testcases/inference/infer_assign_to_implicit_this.dart
index 4973261..6b67ab5 100644
--- a/pkg/front_end/testcases/inference/infer_assign_to_implicit_this.dart
+++ b/pkg/front_end/testcases/inference/infer_assign_to_implicit_this.dart
@@ -65,7 +65,7 @@
 
     var /*@ type=B* */ v7 =
         /*@ type=B* */ /*@target=Test::member*/ /*@target=Test::member*/
-        member /*@ type=B* */ /*@ target=B::- */ --;
+        /*@ type=B* */ member /*@ target=B::- */ --;
   }
 }
 
diff --git a/pkg/front_end/testcases/inference/infer_assign_to_implicit_this_upwards.dart b/pkg/front_end/testcases/inference/infer_assign_to_implicit_this_upwards.dart
index 25db588..20d5671 100644
--- a/pkg/front_end/testcases/inference/infer_assign_to_implicit_this_upwards.dart
+++ b/pkg/front_end/testcases/inference/infer_assign_to_implicit_this_upwards.dart
@@ -25,8 +25,8 @@
         /*@target=Test1::t*/ /*@target=Test1::t*/ t;
 
     var /*@ type=int* */ v11 =
-        /*@ type=int* */ /*@target=Test1::t*/ /*@target=Test1::t*/ t
-        /*@ type=int* */ /*@ target=num::+ */ ++;
+        /*@ type=int* */ /*@target=Test1::t*/ /*@target=Test1::t*/
+        /*@ type=int* */ t /*@ target=num::+ */ ++;
   }
 }
 
@@ -62,8 +62,8 @@
         /*@target=Test2::t*/ /*@target=Test2::t*/ t;
 
     var /*@ type=num* */ v11 =
-        /*@ type=num* */ /*@target=Test2::t*/ /*@target=Test2::t*/ t
-        /*@ type=num* */ /*@ target=num::+ */ ++;
+        /*@ type=num* */ /*@target=Test2::t*/ /*@target=Test2::t*/
+        /*@ type=num* */ t /*@ target=num::+ */ ++;
   }
 }
 
@@ -89,8 +89,8 @@
         /*@target=Test3::t*/ /*@target=Test3::t*/ t;
 
     var /*@ type=double* */ v11 =
-        /*@ type=double* */ /*@target=Test3::t*/ /*@target=Test3::t*/ t
-        /*@ type=double* */ /*@ target=double::+ */ ++;
+        /*@ type=double* */ /*@target=Test3::t*/ /*@target=Test3::t*/
+        /*@ type=double* */ t /*@ target=double::+ */ ++;
   }
 }
 
diff --git a/pkg/front_end/testcases/inference/infer_assign_to_property_full.dart b/pkg/front_end/testcases/inference/infer_assign_to_property_full.dart
index 0fc74d0..457ad54 100644
--- a/pkg/front_end/testcases/inference/infer_assign_to_property_full.dart
+++ b/pkg/front_end/testcases/inference/infer_assign_to_property_full.dart
@@ -62,7 +62,7 @@
         . /*@target=Test::member*/ /*@target=Test::member*/ member;
     var /*@ type=B* */ v7 = /*@ type=Test* */ t
         . /*@ type=B* */ /*@target=Test::member*/ /*@target=Test::member*/
-        member /*@ type=B* */ /*@ target=B::- */ --;
+        /*@ type=B* */ member /*@ target=B::- */ --;
   }
 }
 
diff --git a/pkg/front_end/testcases/inference/infer_assign_to_property_super.dart b/pkg/front_end/testcases/inference/infer_assign_to_property_super.dart
index 26313de..306a3c0 100644
--- a/pkg/front_end/testcases/inference/infer_assign_to_property_super.dart
+++ b/pkg/front_end/testcases/inference/infer_assign_to_property_super.dart
@@ -68,9 +68,8 @@
             . /*@target=Base::member*/ /*@target=Base::member*/ member;
 
     var /*@ type=B* */ v7 = super
-            . /*@ type=B* */ /*@target=Base::member*/ /*@target=Base::member*/
-            member
-        /*@ type=B* */ /*@ target=B::- */ --;
+        . /*@ type=B* */ /*@target=Base::member*/ /*@target=Base::member*/
+        /*@ type=B* */ member /*@ target=B::- */ --;
   }
 }
 
diff --git a/pkg/front_end/testcases/inference/infer_assign_to_property_super_upwards.dart b/pkg/front_end/testcases/inference/infer_assign_to_property_super_upwards.dart
index 804769e..9bda9ca 100644
--- a/pkg/front_end/testcases/inference/infer_assign_to_property_super_upwards.dart
+++ b/pkg/front_end/testcases/inference/infer_assign_to_property_super_upwards.dart
@@ -33,7 +33,7 @@
 
     var /*@ type=int* */ v11 = super
         . /*@ type=int* */ /*@target=Base::intProp*/ /*@target=Base::intProp*/
-        intProp /*@ type=int* */ /*@ target=num::+ */ ++;
+        /*@ type=int* */ intProp /*@ target=num::+ */ ++;
   }
 }
 
@@ -77,10 +77,9 @@
         . /*@target=Base::numProp*/ /*@target=Base::numProp*/ numProp;
 
     var /*@ type=num* */ v11 = super
-            .
-            /*@ type=num* */ /*@target=Base::numProp*/ /*@target=Base::numProp*/
-            numProp
-        /*@ type=num* */ /*@ target=num::+ */ ++;
+        .
+        /*@ type=num* */ /*@target=Base::numProp*/ /*@target=Base::numProp*/
+        /*@ type=num* */ numProp /*@ target=num::+ */ ++;
   }
 }
 
@@ -109,9 +108,8 @@
         . /*@target=Base::doubleProp*/ /*@target=Base::doubleProp*/ doubleProp;
 
     var /*@ type=double* */ v11 = super
-            . /*@ type=double* */ /*@target=Base::doubleProp*/ /*@target=Base::doubleProp*/
-            doubleProp
-        /*@ type=double* */ /*@ target=double::+ */ ++;
+        . /*@ type=double* */ /*@target=Base::doubleProp*/ /*@target=Base::doubleProp*/
+        /*@ type=double* */ doubleProp /*@ target=double::+ */ ++;
   }
 }
 
diff --git a/pkg/front_end/testcases/inference/infer_assign_to_property_upwards.dart b/pkg/front_end/testcases/inference/infer_assign_to_property_upwards.dart
index 10dac09..3928be0 100644
--- a/pkg/front_end/testcases/inference/infer_assign_to_property_upwards.dart
+++ b/pkg/front_end/testcases/inference/infer_assign_to_property_upwards.dart
@@ -25,7 +25,7 @@
         . /*@target=Test1::prop*/ /*@target=Test1::prop*/ prop;
     var /*@ type=int* */ v11 = /*@ type=Test1* */ t
         . /*@ type=int* */ /*@target=Test1::prop*/ /*@target=Test1::prop*/
-        prop /*@ type=int* */ /*@ target=num::+ */ ++;
+        /*@ type=int* */ prop /*@ target=num::+ */ ++;
   }
 }
 
@@ -61,7 +61,7 @@
         . /*@target=Test2::prop*/ /*@target=Test2::prop*/ prop;
     var /*@ type=num* */ v11 = /*@ type=Test2* */ t
         . /*@ type=num* */ /*@target=Test2::prop*/ /*@target=Test2::prop*/
-        prop /*@ type=num* */ /*@ target=num::+ */ ++;
+        /*@ type=num* */ prop /*@ target=num::+ */ ++;
   }
 }
 
@@ -91,7 +91,7 @@
         prop;
     var /*@ type=double* */ v11 = /*@ type=Test3* */ t.
         /*@ type=double* */ /*@target=Test3::prop*/ /*@target=Test3::prop*/
-        prop /*@ type=double* */ /*@ target=double::+ */ ++;
+        /*@ type=double* */ prop /*@ target=double::+ */ ++;
   }
 }
 
diff --git a/pkg/front_end/testcases/inference_new/infer_assign_to_implicit_this.dart b/pkg/front_end/testcases/inference_new/infer_assign_to_implicit_this.dart
index 0501678..9a3427d 100644
--- a/pkg/front_end/testcases/inference_new/infer_assign_to_implicit_this.dart
+++ b/pkg/front_end/testcases/inference_new/infer_assign_to_implicit_this.dart
@@ -69,7 +69,7 @@
 
     var /*@ type=B* */ v7 =
         /*@ type=B* */ /*@target=Test::member*/ /*@target=Test::member*/
-        member /*@ type=B* */ /*@ target=B::- */ --;
+        /*@ type=B* */ member /*@ target=B::- */ --;
   }
 }
 
diff --git a/pkg/front_end/testcases/inference_new/infer_assign_to_implicit_this_upwards.dart b/pkg/front_end/testcases/inference_new/infer_assign_to_implicit_this_upwards.dart
index e042927..5e7045f 100644
--- a/pkg/front_end/testcases/inference_new/infer_assign_to_implicit_this_upwards.dart
+++ b/pkg/front_end/testcases/inference_new/infer_assign_to_implicit_this_upwards.dart
@@ -33,8 +33,8 @@
         /*@target=Test1::t*/ /*@target=Test1::t*/ t;
 
     var /*@ type=int* */ v11 =
-        /*@ type=int* */ /*@target=Test1::t*/ /*@target=Test1::t*/ t
-        /*@ type=int* */ /*@ target=num::+ */ ++;
+        /*@ type=int* */ /*@target=Test1::t*/ /*@target=Test1::t*/
+        /*@ type=int* */ t /*@ target=num::+ */ ++;
   }
 }
 
@@ -70,8 +70,8 @@
         /*@target=Test2::t*/ /*@target=Test2::t*/ t;
 
     var /*@ type=num* */ v11 =
-        /*@ type=num* */ /*@target=Test2::t*/ /*@target=Test2::t*/ t
-        /*@ type=num* */ /*@ target=num::+ */ ++;
+        /*@ type=num* */ /*@target=Test2::t*/ /*@target=Test2::t*/
+        /*@ type=num* */ t /*@ target=num::+ */ ++;
   }
 }
 
@@ -102,8 +102,8 @@
         /*@ target=double::+ */ ++ /*@target=Test3::t*/ /*@target=Test3::t*/ t;
 
     var /*@ type=double* */ v11 =
-        /*@ type=double* */ /*@target=Test3::t*/ /*@target=Test3::t*/ t
-        /*@ type=double* */ /*@ target=double::+ */ ++;
+        /*@ type=double* */ /*@target=Test3::t*/ /*@target=Test3::t*/
+        /*@ type=double* */ t /*@ target=double::+ */ ++;
   }
 }
 
diff --git a/pkg/front_end/testcases/inference_new/infer_assign_to_property.dart b/pkg/front_end/testcases/inference_new/infer_assign_to_property.dart
index 18e21f8..a15c8d5 100644
--- a/pkg/front_end/testcases/inference_new/infer_assign_to_property.dart
+++ b/pkg/front_end/testcases/inference_new/infer_assign_to_property.dart
@@ -22,9 +22,9 @@
     . /*@target=A::f*/ /*@target=A::f*/ f);
 var v_postfix_pp = (new /*@ type=A* */ A()
     . /*@ type=int* */ /*@target=A::f*/ /*@target=A::f*/
-    f /*@ type=int* */ /*@ target=num::+ */ ++);
+    /*@ type=int* */ f /*@ target=num::+ */ ++);
 var v_postfix_mm = (new /*@ type=A* */ A()
     . /*@ type=int* */ /*@target=A::f*/ /*@target=A::f*/
-    f /*@ type=int* */ /*@ target=num::- */ --);
+    /*@ type=int* */ f /*@ target=num::- */ --);
 
 main() {}
diff --git a/pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart b/pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart
index 1878c4d..57ab96d 100644
--- a/pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart
+++ b/pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart
@@ -18,11 +18,11 @@
     . /*@target=B::a*/ /*@target=B::a*/ a);
 var v_prefix_mm = (/*@ target=A::- */ --new /*@ type=B* */ B()
     . /*@target=B::a*/ /*@target=B::a*/ a);
-var v_postfix_pp =
-    (new /*@ type=B* */ B(). /*@ type=A* */ /*@target=B::a*/ /*@target=B::a*/ a
-        /*@ type=int* */ /*@ target=A::+ */ ++);
-var v_postfix_mm =
-    (new /*@ type=B* */ B(). /*@ type=A* */ /*@target=B::a*/ /*@target=B::a*/ a
-        /*@ type=double* */ /*@ target=A::- */ --);
+var v_postfix_pp = (new /*@ type=B* */ B()
+    . /*@ type=A* */ /*@target=B::a*/ /*@target=B::a*/
+    /*@ type=int* */ a /*@ target=A::+ */ ++);
+var v_postfix_mm = (new /*@ type=B* */ B()
+    . /*@ type=A* */ /*@target=B::a*/ /*@target=B::a*/
+    /*@ type=double* */ a /*@ target=A::- */ --);
 
 main() {}
diff --git a/pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart.strong.expect b/pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart.strong.expect
index e4b1a05..2137e494d 100644
--- a/pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart.strong.expect
+++ b/pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart.strong.expect
@@ -12,15 +12,15 @@
 // var v_prefix_mm = (/*@ target=A::- */ --new /*@ type=B* */ B()
 //                                       ^
 //
-// pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart:23:45: Error: A value of type 'int' can't be assigned to a variable of type 'A'.
+// pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart:23:43: Error: A value of type 'int' can't be assigned to a variable of type 'A'.
 //  - 'A' is from 'pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart'.
-//         /*@ type=int* */ /*@ target=A::+ */ ++);
-//                                             ^
+//     /*@ type=int* */ a /*@ target=A::+ */ ++);
+//                                           ^
 //
-// pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart:26:48: Error: A value of type 'double' can't be assigned to a variable of type 'A'.
+// pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart:26:46: Error: A value of type 'double' can't be assigned to a variable of type 'A'.
 //  - 'A' is from 'pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart'.
-//         /*@ type=double* */ /*@ target=A::- */ --);
-//                                                ^
+//     /*@ type=double* */ a /*@ target=A::- */ --);
+//                                              ^
 //
 import self as self;
 import "dart:core" as core;
@@ -48,12 +48,12 @@
  - 'A' is from 'pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart'.
 var v_prefix_mm = (/*@ target=A::- */ --new /*@ type=B* */ B()
                                       ^" in #t3.{self::B::a}.{self::A::-}(1) as{TypeError} self::A*;
-static field self::A* v_postfix_pp = let final self::B* #t5 = new self::B::•() in let final self::A* #t6 = #t5.{self::B::a} in let final core::int* #t7 = #t5.{self::B::a} = let final<BottomType> #t8 = invalid-expression "pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart:23:45: Error: A value of type 'int' can't be assigned to a variable of type 'A'.
+static field self::A* v_postfix_pp = let final self::B* #t5 = new self::B::•() in let final self::A* #t6 = #t5.{self::B::a} in let final core::int* #t7 = #t5.{self::B::a} = let final<BottomType> #t8 = invalid-expression "pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart:23:43: Error: A value of type 'int' can't be assigned to a variable of type 'A'.
  - 'A' is from 'pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart'.
-        /*@ type=int* */ /*@ target=A::+ */ ++);
-                                            ^" in #t6.{self::A::+}(1) as{TypeError} self::A* in #t6;
-static field self::A* v_postfix_mm = let final self::B* #t9 = new self::B::•() in let final self::A* #t10 = #t9.{self::B::a} in let final core::double* #t11 = #t9.{self::B::a} = let final<BottomType> #t12 = invalid-expression "pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart:26:48: Error: A value of type 'double' can't be assigned to a variable of type 'A'.
+    /*@ type=int* */ a /*@ target=A::+ */ ++);
+                                          ^" in #t6.{self::A::+}(1) as{TypeError} self::A* in #t6;
+static field self::A* v_postfix_mm = let final self::B* #t9 = new self::B::•() in let final self::A* #t10 = #t9.{self::B::a} in let final core::double* #t11 = #t9.{self::B::a} = let final<BottomType> #t12 = invalid-expression "pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart:26:46: Error: A value of type 'double' can't be assigned to a variable of type 'A'.
  - 'A' is from 'pkg/front_end/testcases/inference_new/infer_assign_to_property_custom.dart'.
-        /*@ type=double* */ /*@ target=A::- */ --);
-                                               ^" in #t10.{self::A::-}(1) as{TypeError} self::A* in #t10;
+    /*@ type=double* */ a /*@ target=A::- */ --);
+                                             ^" in #t10.{self::A::-}(1) as{TypeError} self::A* in #t10;
 static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference_new/infer_assign_to_property_full.dart b/pkg/front_end/testcases/inference_new/infer_assign_to_property_full.dart
index 0fc74d0..457ad54 100644
--- a/pkg/front_end/testcases/inference_new/infer_assign_to_property_full.dart
+++ b/pkg/front_end/testcases/inference_new/infer_assign_to_property_full.dart
@@ -62,7 +62,7 @@
         . /*@target=Test::member*/ /*@target=Test::member*/ member;
     var /*@ type=B* */ v7 = /*@ type=Test* */ t
         . /*@ type=B* */ /*@target=Test::member*/ /*@target=Test::member*/
-        member /*@ type=B* */ /*@ target=B::- */ --;
+        /*@ type=B* */ member /*@ target=B::- */ --;
   }
 }
 
diff --git a/pkg/front_end/testcases/inference_new/infer_assign_to_property_super.dart b/pkg/front_end/testcases/inference_new/infer_assign_to_property_super.dart
index 428268a..e3c0fc2 100644
--- a/pkg/front_end/testcases/inference_new/infer_assign_to_property_super.dart
+++ b/pkg/front_end/testcases/inference_new/infer_assign_to_property_super.dart
@@ -68,10 +68,9 @@
         /*@target=Base::member*/ /*@target=Base::member*/ member;
 
     var /*@ type=B* */ v7 = super
-            .
-            /*@ type=B* */ /*@target=Base::member*/ /*@target=Base::member*/
-            member
-        /*@ type=B* */ /*@ target=B::- */ --;
+        .
+        /*@ type=B* */ /*@target=Base::member*/ /*@target=Base::member*/
+        /*@ type=B* */ member /*@ target=B::- */ --;
   }
 }
 
diff --git a/pkg/front_end/testcases/inference_new/infer_assign_to_property_super_upwards.dart b/pkg/front_end/testcases/inference_new/infer_assign_to_property_super_upwards.dart
index d236e96..8773a33 100644
--- a/pkg/front_end/testcases/inference_new/infer_assign_to_property_super_upwards.dart
+++ b/pkg/front_end/testcases/inference_new/infer_assign_to_property_super_upwards.dart
@@ -43,9 +43,8 @@
         . /*@target=Base::intProp*/ /*@target=Base::intProp*/ intProp;
 
     var /*@ type=int* */ v11 = super
-            . /*@ type=int* */ /*@target=Base::intProp*/ /*@target=Base::intProp*/
-            intProp
-        /*@ type=int* */ /*@ target=num::+ */ ++;
+        . /*@ type=int* */ /*@target=Base::intProp*/ /*@target=Base::intProp*/
+        /*@ type=int* */ intProp /*@ target=num::+ */ ++;
   }
 }
 
@@ -89,7 +88,7 @@
 
     var /*@ type=num* */ v11 = super
         . /*@ type=num* */ /*@target=Base::numProp*/ /*@target=Base::numProp*/
-        numProp /*@ type=num* */ /*@ target=num::+ */ ++;
+        /*@ type=num* */ numProp /*@ target=num::+ */ ++;
   }
 }
 
@@ -128,7 +127,7 @@
 
     var /*@ type=double* */ v11 = super
         . /*@ type=double* */ /*@target=Base::doubleProp*/ /*@target=Base::doubleProp*/
-        doubleProp /*@ type=double* */ /*@ target=double::+ */ ++;
+        /*@ type=double* */ doubleProp /*@ target=double::+ */ ++;
   }
 }
 
diff --git a/pkg/front_end/testcases/inference_new/infer_assign_to_property_upwards.dart b/pkg/front_end/testcases/inference_new/infer_assign_to_property_upwards.dart
index 502a144..069816c 100644
--- a/pkg/front_end/testcases/inference_new/infer_assign_to_property_upwards.dart
+++ b/pkg/front_end/testcases/inference_new/infer_assign_to_property_upwards.dart
@@ -32,7 +32,7 @@
     var /*@ type=int* */ v11 =
         /*@ type=Test1* */ t
             . /*@ type=int* */ /*@target=Test1::prop*/ /*@target=Test1::prop*/
-            prop /*@ type=int* */ /*@ target=num::+ */ ++;
+            /*@ type=int* */ prop /*@ target=num::+ */ ++;
   }
 }
 
@@ -66,7 +66,7 @@
     var /*@ type=num* */ v11 =
         /*@ type=Test2* */ t
             . /*@ type=num* */ /*@target=Test2::prop*/ /*@target=Test2::prop*/
-            prop /*@ type=num* */ /*@ target=num::+ */ ++;
+            /*@ type=num* */ prop /*@ target=num::+ */ ++;
   }
 }
 
@@ -96,7 +96,7 @@
     var /*@ type=double* */ v11 =
         /*@ type=Test3* */ t
             . /*@ type=double* */ /*@target=Test3::prop*/ /*@target=Test3::prop*/
-            prop /*@ type=double* */ /*@ target=double::+ */ ++;
+            /*@ type=double* */ prop /*@ target=double::+ */ ++;
   }
 }
 
diff --git a/pkg/front_end/testcases/inference_new/property_assign_combiner.dart b/pkg/front_end/testcases/inference_new/property_assign_combiner.dart
index c38f17d..5b764735 100644
--- a/pkg/front_end/testcases/inference_new/property_assign_combiner.dart
+++ b/pkg/front_end/testcases/inference_new/property_assign_combiner.dart
@@ -51,9 +51,9 @@
 void test3(G g) {
   /*@ type=G* */ g
       . /*@target=G::target*/ /*@target=G::target*/ target /*@ target=A::+ */ ++;
-  var /*@ type=A* */ x = /*@ type=G* */ g
-          . /*@ type=A* */ /*@target=G::target*/ /*@target=G::target*/ target
-      /*@ type=C* */ /*@ target=A::+ */ ++;
+  var /*@ type=A* */ x = /*@ type=G* */ g. /*@ type=A* */ /*@target=G::target*/
+          /*@target=G::target*/ /*@ type=C* */ target
+      /*@ target=A::+ */ ++;
 }
 
 main() {}
diff --git a/pkg/kernel/doc/nnbd_api.md b/pkg/kernel/doc/nnbd_api.md
new file mode 100644
index 0000000..1c6b8d5
--- /dev/null
+++ b/pkg/kernel/doc/nnbd_api.md
@@ -0,0 +1,350 @@
+# Nullability in CFE
+
+Author: The Dart CFE team.
+
+Status: Draft
+
+
+
+## CHANGELOG
+
+2019.09.26:
+- Initial version uploaded.
+
+
+
+## Summary
+
+The sections below describe the encoding of the nullability property on types in the Kernel ASTs produced by the CFE.  Details are discussed, such as the use of `Nullability.neither`, and computation of the nullability property for the results of type substitution and type intersection is described.  The encoding for late fields and variables and required named parameters is described.  Finally, the list of the updates to the public interface of the CFE is given along with some recommendations on updating the client code.
+
+This is a living document describing the changes in the output and in the public interface of the CFE related to the NNBD Dart language feature.  It is being updated as more changes are made.
+
+
+
+## Objective
+
+The document describes the updates in the output and in the API of the CFE related to the NNBD Dart language feature.  The document attempts to suggest the related updates in the client code for some simple cases.
+
+*TODO: Describe non-goals.*
+
+
+
+## Background
+
+[The NNBD Dart language feature](https://github.com/dart-lang/language/blob/master/accepted/future-releases/nnbd/feature-specification.md) allows programmers to define types as nullable using the `?` suffix.  By default, the types are treated as non-nullable.  In addition to that, a [weak mode](https://github.com/dart-lang/language/blob/d4850d8fecaf2547c89f799a1d49a90cc9f935f4/accepted/future-releases/nnbd/roadmap.md#weak-null-checking) is defined that allows programmers to have some of their libraries to be opted out of the NNBD feature.  The types in the opted-out libraries are called legacy types and should be accounted for when they meet with nullable or non-nullable types on the library borders, for example in subtype checks.  Finally, there are types in the opted-in libraries that can't be classified as either nullable or non-nullable at compile time.
+
+The presence of the nullability property on types affects some of the existing algorithms, such as type checks or type inference.  It also introduces additional notions and algorithms that are convenient and sometimes necessary to work with nullable types.
+
+NNBD adds a number of features to the language that are not purely syntactic and should be communicated from the CFE to the back ends.  This document describes the related changes in the CFE output as well as the related changes in the API of the CFE libraries.
+
+
+
+## Overview
+
+The nullability property on types is represented by an `enum` with four possible values: for nullable types, non-nullable types, legacy types, and the types the nullability of which can't be fully determined at compile type.
+
+It is required to compute the nullability of types and their parts when performing type substitution and creating an intersection of two types (also known as type-parameter types with promoted bounds).  There are tables that describe those two functions for combining nullabilities.
+
+In addition to the nullability property on types there are new flags on the relevant nodes that mark the use of `late` and `required` keywords.  There's also a new Kernel AST node for the null check operator.
+
+There's a number of changes in the API of the CFE.  The most notable changes are the removal of the `Class.rawType` getter and the related getters on `TypeEnvironment`.  There's a number of nullability-aware getters and methods that are added on `CoreTypes` that should be used instead of the removed getters.
+
+To help avoid the explicit use of legacy types, there are getters on the `Library` AST node that help with choosing the appropriate nullability for the library depending on its opt-in status for the NNBD feature.  Some recommendations are given for using those getters.
+
+
+
+## Detailed Design
+
+
+### Terminology
+
+In the document the term _type parameter_ is used to describe a formal type parameter of a class, a type alias, or a generic function.  For example,`X` and `Y` are type parameters in the declaration `class A<X, Y> {}`.  The term _type argument_ is used to describe an actual type parameter in an instance of a generic class or a type alias or an invocation of a generic function or a constructor of a generic class.  For example, `int` and `List<String>` are type arguments in the expression `new Map<int, List<String>>()`.
+
+
+### Encoding for Nullability
+
+The CFE combines various bits of information available at compile time, such as the nullability markers `?` used by the programmer and the NNBD opted-in status of the libraries, to mark every `DartType` in its output as belonging to one of the following four mutually disjoint sets:
+
+- **Nullable** types.  Mainly, these are the types that are marked with `?` by the programmer.  They can also be inferred from other nullable types or synthesized according to the language specification.  For example, if the programmer omits the type bound on a type variable in an opted-in library, the CFE should synthesize `Object?` for the bound.
+- **Non-nullable** types.  This is the default category of types.  If a type is declared without any modifiers in an opted-in library, in most cases it would be non-nullable.
+- Types in opted-in libraries that are potentially nullable or potentially non-nullable, but **neither** can be said about them at compile time.  An example of such type is a type-parameter type with the nullable bound.  At run time both nullable and non-nullable types can be passed for that type parameter, so it's impossible to say anything about the nullability of such type at compile time.
+- **Legacy** types.  These are the types originating from the opted-out libraries.
+
+Every `DartType` subclass implements the `nullability` getter.  The return value of the getter is described by the following [`enum`](https://github.com/dart-lang/sdk/blob/0a4d47de3cb8cd398c5a2c669953129cdb11ec9a/pkg/kernel/lib/ast.dart#L4803):
+
+```dart
+enum Nullability {
+  nullable,
+  nonNullable,
+  neither,
+  legacy
+}
+```
+
+In the textual representation of Kernel that is commonly used in `.expect` files `Nullability.nullable` is printed out as `?`, `Nullability.nonNullable` is printed as an empty sequence of characters, `Nullability.neither` is printed as `%`, and `Nullability.legacy` is printed as `*`.
+
+*TODO: Add an example of a .expect file.*
+
+
+####The 'neither' Nullability
+
+`Nullability.neither` marks all types that can't be put into any other three categories at compile time and that should be categorized at run time.  The primary use case for `Nullability.neither` are type-parameter types with nullable bounds.  Consider the following Dart program:
+
+```dart
+// The enclosing library is opted in.
+
+class A<T extends Object?> {
+  foo(T x) {
+    x = null;         // Compile-time error.
+    Object y = x;     // Compile-time error.
+
+    bar(T z) {}
+    dynamic f = bar;
+    f?.call(null);    // Runtime error?
+  }
+}
+```
+
+At compile time nothing can be said about the nullability of `T` because it is possible that at run time either a nullable or non-nullable type will be passed for it.  We have to be restrictive and prohibit both assignments of `null` to variables of type `T` and assignments of expression values of type `T` to variables of non-nullable types.  However, there are cases when the error can be caught only at run time when the nullability of the type passed for `T` is known.  An example of that is an invocation of a function stored in a variable of type `dynamic`.
+
+A type-parameter type also has `Nullability.neither` if its bound have `Nullability.neither`.  In the following example types `T`, `S`, and `V` are of `neither` nullability:
+
+```dart
+class B<T extends S, S extends V, V extends Object?> {
+  foo(T t, S s, V v) {
+    // ...
+  }
+}
+```
+
+Additionally, if the nullability of a type depends on the nullability of an `InvalidType`, the former is set to `Nullability.neither` for recovery purposes.  An example of such dependency is the nullability of a type-parameter type with an `InvalidType` as the bound of its type parameter.  Note that the `.nullability` getter of `InvalidType` throws when accessed in order to make sure all such dependencies are treated explicitly.
+
+
+#### Type Substitution and Nullability
+
+Substitution of type arguments for occurrences of type parameters, when both the former and the latter have nullability attributes, requires computing the nullability of the substitution result.
+
+In the following table the rows correspond to the possible nullability attributes of the type argument, the columns correspond to the possible nullability attributes of the type parameters, and the table elements contain the nullability for the result of the substitution of a type argument for a type parameter with the corresponding nullabilities.
+
+| arg \ var | ! | ? | * | % |
+|---|---|---|---|---|
+| ! | ! | ? | * | ! |
+| ? | N/A | ? | ? | ? |
+| * | * | ? | * | * |
+| % | N/A | ? | * | % |
+
+In the table `!` denotes `Nullability.nonNullable`, `?` denotes `Nullability.nullable`, `*` denotes `Nullability.legacy`, and `%` denotes `Nullability.neither`.
+
+Type-parameter types are assigned their nullabilities as follows:
+
+- If a type parameter has a non-nullable bound, and a type-parameter type referring to that type parameter isn't marked with `?`, then that type-parameter type is non-nullable.  In the following example both `X` and `Y` are non-nullable when used as types:
+
+```dart
+class A<X extends Object> { X foo() => null; }
+typedef F<Y extends int> = Y Function();
+```
+
+- If a type-parameter type is marked with `?`, the resulting type is nullable regardless of the nullability of the bound.  In the following example, types of all positional parameters of `foo` are nullable:
+
+```dart
+class A<X extends Object, Y extends Object?, Z extends Y> {
+  foo(X? x, Y? y, Z? z) {}
+}
+```
+
+- If a type-parameter type is used in an opted-out library, it's nullability is `Nullability.legacy` regardless of the nullability of the bound.  Note that in the following example both `X` and `Y` are legacy types despite `Y` having the nullable type `dynamic` as the bound.
+
+```dart
+// Assume the library is opted out.
+class A<X extends int, Y extends dynamic> { foo(X x, Y y) {} }
+```
+
+- If a type parameter has a nullable bound or a bound that has `Nullability.neither`, and a type-parameter type referring that type parameter isn't marked with `?`, then that type-parameter type has `Nullability.neither`.  In the following example `X`, `Y`, and `Z` have `Nullability.neither` when used as types:
+
+```dart
+// Note that 'Object?' is provided for the omitted bounds in opted-in libraries.
+class A<X extends Y, Y extends Z, Z> { foo(X x, Y y, Z z) {} }
+```
+
+All four cases above describe not promoted type-parameter types. Promoted type-parameter types are discussed in section **Nullability of Intersection Types**.
+
+Type substitution happens both at compile time and at run time.  Unaliasing a `TypedefType`, such as the return type of `foo` in `typedef F<X, Y> = X Function(Y?); F<int?, String> foo() => null;`, is an example of type substitution happening at compile time.  The corresponding CFE output for the example looks as follows:
+
+```kernel
+library;
+import self as self;
+import "dart:core" as core;
+
+typedef F<X extends core::Object? = dynamic, contravariant Y extends core::Object? = dynamic> = (Y?) → X%;
+static method foo() → (core::String?) → core::int?
+  return null;
+```
+
+Note that `X` has `Nullability.neither` when used as a type in the right-hand side of the `typedef` declaration.  The return type of `foo` is `int? Function(String?)`, which is the result of substituting `X` with `int?` and `Y` with `String` in `X% Function(Y?)`.
+
+Obtaining the type for a type check, such as the is-check in the body of `foo` in the program fragment below, is an example where type substitution is needed at run time. 
+
+```dart
+class A<X> {
+  foo(dynamic bar) => bar is List<X>;
+}
+```
+
+The elements of the table that are marked with N/A correspond to cases that should be rejected by a type check.  The case for type argument having `Nullability.nullable` and the type parameter having `Nullability.nonNullable` should result in a type error because a nullable type can't be a subtype of a non-nullable type.  Similar is true for the argument that have `Nullability.neither` and the type parameter that have `Nullability.nonNullable` because at run time `Nullability.neither` can be replaced with `Nullability.nullable`.
+
+The substitution routines in `pkg/kernel/lib/type_algebra.dart` follow the nullability computation rules described above.
+
+
+#### Nullability of Intersection Types
+
+In Kernel `TypeParameterType` represents types of two kinds.  The primary purpose of the node is to denote an occurrence of a type parameter in another type, which can be the entire type in the simplest case.  The secondary purpose of `TypeParameterType` is to represent a limited intersection type that arises from type promotion of variables declared with a `TypeParameterType`.  In the latter case the overall nullability of the intersection type is computed from the nullabilities of the left-hand side of the intersection (referred to as LHS below) and the right-hand side of the intersection (referred to as RHS below).
+
+In the following table the rows correspond to the possible nullability attributes of the LHS, the columns correspond to the possible nullability attributes of the RHS, and the table elements contain the nullability of the intersection type of two types with the corresponding nullabilities.
+
+| LHS \ RHS | ! | ? | * | % |
+|---|---|---|---|---|
+| ! | ! | N/A | N/A | ! |
+| ? | N/A | N/A | N/A | N/A |
+| * | N/A | N/A | * | N/A |
+| % | ! | % | N/A | % |
+
+In the table `!` denotes `Nullability.nonNullable`, `?` denotes `Nullability.nullable`, `*` denotes `Nullability.legacy`, and `%` denotes `Nullability.neither`.
+
+The table elements marked with N/A represent combinations that can't be a part of a well-formed CFE output.  Some of them are due to the restriction on the intersection type that the RHS of the intersection should be a subtype of the bound of the type variable, and some others are due to the restriction that a nullable type is never promoted to an intersection type.
+
+The intersection is induced by some of the type promotions, such as the one in the example below.
+
+```dart
+class A<T extends num?> {
+  foo(T t) {
+    if (t is int?) {
+      var bar = t;
+    }
+  }
+}
+```
+
+The type of the variable `t` in the example is promoted from `T` to `T & int?` because the RHS of the intersection, namely `int?`, is a subtype of the bound of `T`, which is `num?`.  In Kernel `T` has `Nullability.neither` because the bound of `T` is nullable, and the intersection type with the nullabilities of all its parts looks like `T% & int?`.  The following is the textual representation of the program from the example above compiled by the CFE.
+
+```kernel
+library;
+import self as self;
+import "dart:core" as core;
+
+class A<T extends core::num? = core::num?> extends core::Object {
+  synthetic constructor •() → self::A<self::A::T*>*
+    : super core::Object::•()
+    ;
+  method foo(generic-covariant-impl self::A::T% t) → dynamic {
+    if(t is core::int?) {
+      self::A::T% & core::int? /* '%' & '?' = '%' */ bar = t{self::A::T% & core::int? /* '%' & '?' = '%' */};
+    }
+  }
+}
+```
+
+Note that the type of `t`, which is written in the curly braces right after the getter, inside of the promoting if-statement is an intersection type with `self::A::T%` as the LHS and `core::int?` as the RHS.  The comments generated by the textual serializer show the computation of the overall nullability of the intersection type from the nullabilities of its components.
+
+Instead of having the overall nullability on the `TypeParameterType` object, only the nullability of the LHS is serialized as the field `TypeParameterType.typeParameterTypeNullability`, and the overall nullability is computed in the `TypeParameterType.nullability` getter.  The back ends that perform their own deserialization may want to implement the computation of the overall nullability following that in the `TypeParameterType.nullability` getter.
+
+
+### The 'required' Flag
+
+Named parameters can be declared using the `required` keyword.  To reflect the use of the keyword the CFE sets the `isRequired` flag on `VariableDeclaration` and `NamedType` nodes.
+
+The `isRequired` flag on `VariableDeclaration` is set if the node encodes a named formal parameter and the `required` keyword was used.
+
+The use of the `required` keyword affects the override rules and the subtyping relationship for function types.  To reflect the use of the keyword in a function type, the `isRequired` flag is set on the corresponding `NamedType` representing the type of the named parameter.
+
+
+### The 'late' Flag on Variables and Fields
+
+Fields and variables can be declared using the `late` keyword.  To reflect the use of the keyword the CFE sets the `isLate` flag on `Field` and `VariableDeclaration` nodes.
+
+The plan is to provide an optional desugaring of `late` fields and variables to aid the initial implementation of the feature.  The desugaring could be turned on by back ends via a compilation-target flag.
+
+*TODO: Expand the section on desugaring.*
+
+
+### The Null Check Operator
+
+*TODO: Update the section.*
+
+
+### Updates to the API
+
+*TODO: Update the section as API changes.*
+
+#### 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`).
+- 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.
+
+#### isRequired and isLate flags
+
+- `VariableDeclaration.isRequired` setter and getter are added.
+- `NamedType.isRequired` final field is added.
+- `VariableDeclaration.isLate` setter and getter are added.
+- `Field.isLate` setter and getter are added.
+
+#### Null Check
+
+- `NullCheck` AST node is added.
+
+#### Changes in caching of raw types
+- `Class.rawType` is removed.
+- `TypeEnvironment.*Type` where `*` expands to `object`, `bool`, `int`, `num`, `double`, `string`, `symbol`, `type`, `rawFunction` are removed.
+- `CoreTypes.*NonNullableRawType`, `CoreTypes.*NullableRawType`, `CoreTypes.*LegacyRawType`, and `CoreTypes.*RawType(Nullability)` where `*` expands into `object`, `bool`, `int`, `num`, `double`, `string`, `list`, `set`, `map`, `iterable`, `iterator`, `symbol`, `type`, `function`, `invocation`, `invocationMirror`, `future`, `stackTrace`, `stream`, `asyncAwaitCompleter`, `futureOr`, and `pragma` are added.
+- `CoreTypes.nullType` is added.
+- `CoreTypes.nonNullableRawType(Class)`, `CoreTypes.nullableRawType(Class)`, `CoreTypes.legacyRawType(Class)`, and `CoreTypes.rawType(Class, Nullability)` are added.
+
+The reason for the changes is to avoid having type objects of undefined nullability and have nullability-aware getters and methods for retrieving the types instead.  The changes that landed the update ([commit 515a5977](https://github.com/dart-lang/sdk/commit/515a597710ace5b089d92c4bf3ebbfd0c61d7186), [commit e034104f](https://github.com/dart-lang/sdk/commit/e034104f04948ab9d5dc38a603841a70d0090812)) also change the client code so that a legacy type is retrieved from `CoreTypes` whenever there was an invocation of `Class.rawType`.  All of those places should be updated to retrieve a type with the desired nullability (see section **Updating the Client Code**).
+
+#### Library status and library-specific nullability treatment
+- `Library.isNonNullableByDefault` is added.
+- `Library.nullable`, `Library.nonNullable`, and `Library.nullableIfTrue(bool)` are added.
+
+The `Library.isNonNullableByDefault` getter is added to distinguish between opted-in and opted-out libraries.  Right now it returns `true` if the `non-nullable` experiment is enabled, and `false` otherwise.
+
+The `Library.nullable` and `Library.nonNullable` getters are added to simplify the reasoning about types in the CFE and in the client code.  They return `Nullability.nullable` and `Nullability.nonNullable` respectively if the library is opted in, and both return `Nullability.legacy` otherwise.  Thus, one may only consider what nullability would be desirable in an opted-in library and have the case of opted-out library covered by the getters.
+
+Similarly, `Library.nullableIfTrue(bool)` converts a boolean into a `Nullability` value: `true` is converted into `Nullability.nullable` and `false` is converted into `Nullability.nonNullable` if the library is opted in.  If the library is opted out, `Library.nullableIfTrue(bool)` returns `Nullability.legacy`.
+
+This set of members makes it possible to avoid the explicit use of `Nullability.legacy` in the CFE and the client code.
+
+
+### Updating the Client Code ###
+
+#### Avoiding explicit legacy
+
+As described in section **Changes in caching of raw types**, all previously existing invocations of `Class.rawType` and of the related getters of `TypeEnvironment` were replaced with invocations of nullability-aware members of `CoreTypes`.  To keep the observable behavior of the client code, legacy types were used wherever before a raw type was used.  For example, `intClass.rawType` was replaced with `coreTypes.intLegacyRawType` and `cls.rawType` was replaced with `coreTypes.legacyRawType(cls)`.  All of those call sites should be updated as a part of the NNBD feature implementation because they are the source of legacy types regardless of the opted-in status of the library they are generated for.  Section **Library status and library-specific nullability treatment** describes the changes in the CFE public interface that are supposed to help with the process.
+
+The easiest way to avoid using explicitly legacy types is to do the following:
+
+1.  Decide which nullability would be desirable for the type in an opted-in library.
+2.  Specify the desired nullability for the type with `.nullable` or `.nonNullable` getter on the library node of the library that the type is used in.  In some cases, when a boolean condition tells if a type should be nullable, `.nullableIfTrue(bool)` method on the library node may be useful.
+
+Quick recommendations for updating the described code are listed below.  The examples use `Nullability.nonNullable` as the desired nullability.
+
+- Replace `coreTypes.intLegacyRawType` with `coreTypes.intRawType(library.nonNullable)`.  Similarly for other built-in types.
+- Replace `coreTypes.legacyRawType(cls)` with `coreTypes.rawType(cls, library.nonNullable)`.
+- Replace `coreTypes.rawType(cls, Nullability.legacy)` with `coreTypes.rawType(cls, library.nonNullable)`.
+- Replace `new InterfaceType(cls, typeArgs)` with `new InterfaceType(cls, typeArgs, library.nonNullable)`.
+- Replace `new InterfaceType(cls)` with `new InterfaceType(cls, const <DartType>[], library.nonNullable)`.
+- Replace `new InterfaceType.byReference(clsRef, typeArgs)` with `new InterfaceType.byReference(clsRef, typeArgs, library.nonNullable)`.
+- Replace `new FunctionType(positional, retType, <NAMED>)` with `new FunctionType(positional, retType, nullability: library.nonNullable, <NAMED>)` where `<NAMED>` are the named arguments passed in.
+- Replace `new TypedefType(tdef, typeArgs)` with `new TypedefType(tdef, typeArgs, library.nonNullable)`.
+- Replace `new TypedefType(tdef)` with `new TypedefType(tdef, const <DartType>[], library.nonNullable)`.
+- Replace `new TypedefType.byReference(tdefRef, typeArgs)` with `new TypedefType.byReference(tdefRef, typeArgs, library.nonNullable)`.
+
+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.
+
+#### 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.
+
+#### Type equality
+
+*TODO: Update the section.*
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index 7fa652c..239a4ae 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -563,7 +563,7 @@
     } else {
       _handleAssignment(defaultValue,
           destinationType: getOrComputeElementType(node.declaredElement),
-          canInsertChecks: false);
+          fromDefaultValue: true);
     }
     return null;
   }
@@ -1591,7 +1591,7 @@
       Expression destinationExpression,
       AssignmentExpression compoundOperatorInfo,
       Expression questionAssignNode,
-      bool canInsertChecks = true}) {
+      bool fromDefaultValue = false}) {
     assert(
         (destinationExpression == null) != (destinationType == null),
         'Either destinationExpression or destinationType should be supplied, '
@@ -1610,6 +1610,7 @@
         destinationType = destinationExpression.accept(this);
       }
     }
+
     if (questionAssignNode != null) {
       _guards.add(destinationType.node);
     }
@@ -1620,12 +1621,18 @@
         throw StateError('No type computed for ${expression.runtimeType} '
             '(${expression.toSource()}) offset=${expression.offset}');
       }
-      ExpressionChecksOrigin expressionChecksOrigin;
-      if (canInsertChecks && !sourceType.type.isDynamic) {
-        expressionChecksOrigin = ExpressionChecksOrigin(
-            source, expression, ExpressionChecks(expression.end));
-        _variables.recordExpressionChecks(
-            source, expression, expressionChecksOrigin);
+      EdgeOrigin edgeOrigin;
+      if (!sourceType.type.isDynamic) {
+        if (fromDefaultValue) {
+          edgeOrigin = DefaultValueOrigin(source, expression);
+        } else {
+          ExpressionChecksOrigin expressionChecksOrigin =
+              ExpressionChecksOrigin(
+                  source, expression, ExpressionChecks(expression.end));
+          _variables.recordExpressionChecks(
+              source, expression, expressionChecksOrigin);
+          edgeOrigin = expressionChecksOrigin;
+        }
       }
       if (compoundOperatorInfo != null) {
         var compoundOperatorMethod = compoundOperatorInfo.staticElement;
@@ -1639,7 +1646,7 @@
           DecoratedType compoundOperatorType =
               getOrComputeElementType(compoundOperatorMethod);
           assert(compoundOperatorType.positionalParameters.length > 0);
-          _checkAssignment(expressionChecksOrigin,
+          _checkAssignment(edgeOrigin,
               source: sourceType,
               destination: compoundOperatorType.positionalParameters[0],
               hard: _postDominatedLocals.isReferenceInScope(expression));
@@ -1654,10 +1661,11 @@
           sourceType = _dynamicType;
         }
       } else {
-        _checkAssignment(expressionChecksOrigin,
+        _checkAssignment(edgeOrigin,
             source: sourceType,
             destination: destinationType,
-            hard: _postDominatedLocals.isReferenceInScope(expression));
+            hard: questionAssignNode == null &&
+                _postDominatedLocals.isReferenceInScope(expression));
       }
       if (questionAssignNode != null) {
         // a ??= b is only nullable if both a and b are nullable.
@@ -2153,6 +2161,21 @@
       {@required DecoratedType source,
       @required DecoratedType destination,
       @required bool hard}) {
+    var sourceType = source.type;
+    var destinationType = destination.type;
+    if (!_typeSystem.isSubtypeOf(sourceType, destinationType)) {
+      // Not a proper upcast assignment.
+      if (_typeSystem.isSubtypeOf(destinationType, sourceType)) {
+        // But rather a downcast.
+        _checkDowncast(origin,
+            source: source, destination: destination, hard: hard);
+        return;
+      }
+      // Neither a proper upcast assignment nor an implicit downcast (some
+      // illegal code, or we did something wrong to get here).
+      assert(false, 'side cast not supported: $sourceType to $destinationType');
+      return;
+    }
     _connect(source.node, destination.node, origin, hard: hard);
     _checkAssignment_recursion(origin,
         source: source, destination: destination);
@@ -2165,35 +2188,7 @@
       {@required DecoratedType source, @required DecoratedType destination}) {
     var sourceType = source.type;
     var destinationType = destination.type;
-    if (!_typeSystem.isSubtypeOf(sourceType, destinationType)) {
-      // Not a proper upcast assignment.  It is either an implicit downcast or
-      // some illegal code.  It's handled on a "best effort" basis.
-      if (destinationType is TypeParameterType &&
-          sourceType is! TypeParameterType) {
-        // Assume an assignment to the type parameter's bound.
-        _checkAssignment(origin,
-            source: source,
-            destination:
-                _getTypeParameterTypeBound(destination).withNode(_graph.always),
-            hard: false);
-        return;
-      }
-      if (sourceType is InterfaceType && destinationType is InterfaceType) {
-        if (_typeSystem.isSubtypeOf(destinationType, sourceType)) {
-          var rewrittenDestination = _decoratedClassHierarchy.asInstanceOf(
-              destination, sourceType.element);
-          assert(rewrittenDestination.typeArguments.length ==
-              source.typeArguments.length);
-          for (int i = 0; i < rewrittenDestination.typeArguments.length; i++) {
-            _checkAssignment(origin,
-                source: source.typeArguments[i],
-                destination: rewrittenDestination.typeArguments[i],
-                hard: false);
-          }
-        }
-      }
-      return;
-    }
+    assert(_typeSystem.isSubtypeOf(sourceType, destinationType));
     if (destinationType.isDartAsyncFutureOr) {
       var s1 = destination.typeArguments[0];
       if (sourceType.isDartAsyncFutureOr) {
@@ -2327,6 +2322,63 @@
     }
   }
 
+  void _checkDowncast(EdgeOrigin origin,
+      {@required DecoratedType source,
+      @required DecoratedType destination,
+      @required bool hard}) {
+    assert(_typeSystem.isSubtypeOf(destination.type, source.type));
+    // Nullability should narrow to maintain subtype relationship.
+    _connect(source.node, destination.node, origin, hard: hard);
+    if (source.type.isDynamic) {
+      assert(destination.typeFormals?.isEmpty ?? true,
+          'downcast to something with type parameters not yet supported.');
+      assert(destination is! FunctionType,
+          'downcast to function type not yet supported.');
+      if (destination.type is ParameterizedType) {
+        for (final param
+            in (destination.type as ParameterizedType).typeParameters) {
+          assert(param.type.bound.isDynamic,
+              'downcast to type parameters with bounds not supported');
+        }
+      }
+
+      for (final arg in destination.typeArguments) {
+        // We cannot assume we're downcasting to C<T!>. Downcast to C<T?>.
+        _checkDowncast(origin, source: source, destination: arg, hard: false);
+      }
+    } else if (destination.type is TypeParameterType &&
+        source.type is! TypeParameterType) {
+      // Assume an assignment to the type parameter's bound.
+      _checkAssignment(origin,
+          source: source,
+          destination:
+              _getTypeParameterTypeBound(destination).withNode(_graph.always),
+          hard: false);
+    } else if (destination.type is InterfaceTypeImpl) {
+      assert(source.typeArguments.isEmpty,
+          'downcast from interface type with type args not supported.');
+      if (destination.type is ParameterizedType) {
+        for (final param
+            in (destination.type as ParameterizedType).typeParameters) {
+          assert(param.type.bound.isDynamic,
+              'downcast to type parameters with bounds not supported');
+        }
+      }
+      for (final arg in destination.typeArguments) {
+        // We cannot assume we're downcasting to C<T!>. Downcast to C<T?>.
+        _checkDowncast(origin,
+            source: DecoratedType(_typeProvider.dynamicType, _graph.always),
+            destination: arg,
+            hard: false);
+      }
+    } else {
+      assert(
+          false,
+          'downcasting from ${source.type.runtimeType} to '
+          '${destination.type.runtimeType} not supported.');
+    }
+  }
+
   void _connect(
       NullabilityNode source, NullabilityNode destination, EdgeOrigin origin,
       {bool hard = false});
diff --git a/pkg/nnbd_migration/lib/src/edge_origin.dart b/pkg/nnbd_migration/lib/src/edge_origin.dart
index 27db686..94133d5 100644
--- a/pkg/nnbd_migration/lib/src/edge_origin.dart
+++ b/pkg/nnbd_migration/lib/src/edge_origin.dart
@@ -28,6 +28,12 @@
   AssignmentExpression get node => super.node as AssignmentExpression;
 }
 
+/// An edge origin used for edges that originated because of a default value on
+/// a parameter.
+class DefaultValueOrigin extends EdgeOrigin {
+  DefaultValueOrigin(Source source, Expression node) : super(source, node);
+}
+
 /// Common interface for classes providing information about how an edge came
 /// to be; that is, what was found in the source code that led the migration
 /// tool to create the edge.
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index 0a81426..315052a 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -981,6 +981,82 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  @failingTest
+  test_downcast_not_widest_type_type_parameters() async {
+    // Fails because a hard assignment from List<int/*1*/> to List<int/*2*/>
+    // doesn't create a hard edge from 1 to 2. Perhaps this is correct. In this
+    // example it seems incorrect.
+    var content = '''
+void f(dynamic a) {
+  List<int> hardToNonNullNonNull = a;
+  List<int> hardToNullNonNull = a;
+  List<int> hardToNonNullNull = a;
+  List<int/*!*/>/*!*/ nonNullNonNull;
+  List<int/*?*/>/*!*/ nullNonNull;
+  List<int/*!*/>/*?*/ nonNullNull;
+  nonNullNonNull = hardToNonNullNonNull
+  nonNullNull = hardToNonNullNull
+  nullNonNull = hardToNullNonNull
+}
+''';
+
+    // TODO(paulberry): remove the /*!*/, /*?*/ comments on migration.
+    var expected = '''
+void f(dynamic a) {
+  List<int> hardToNonNullNonNull = a;
+  List<int?> hardToNullNonNull = a;
+  List<int>? hardToNonNullNull = a;
+  List<int/*!*/>/*!*/ nonNullNonNull;
+  List<int/*?*/>/*!*/ nullNonNull;
+  List<int/*!*/>/*?*/ nonNullNull;
+  nonNullNonNull = hardToNonNullNonNull
+  nonNullNull = hardToNonNullNull
+  nullNonNull = hardToNullNonNull
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  @failingTest
+  test_downcast_widest_type_from_related_type_parameters() async {
+    var content = '''
+List<int> f(Iterable<int/*?*/> a) => a;
+''';
+
+    // TODO(paulberry): remove the /*!*/, /*?*/ comments on migration.
+    var expected = '''
+List<int?> f(Iterable<int/*?*/> a) => a;
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  test_downcast_widest_type_from_top_type_parameters() async {
+    var content = '''
+List<int> f1(dynamic a) => a;
+List<int> f2(Object b) => b;
+''';
+    var expected = '''
+List<int?>? f1(dynamic a) => a;
+List<int?> f2(Object b) => b;
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  @failingTest
+  test_downcast_widest_type_from_unrelated_type_parameters() async {
+    var content = '''
+abstract class C<A, B> implements List<A> {}
+C<int, num> f(List<int> a) => a;
+''';
+
+    // TODO(paulberry): remove the /*!*/, /*?*/ comments on migration.
+    var expected = '''
+abstract class C<A, B> implements List<A> {}
+C<int, num?> f(List<int> a) => a;
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
   test_dynamic_method_call() async {
     var content = '''
 class C {
diff --git a/pkg/nnbd_migration/test/edge_builder_test.dart b/pkg/nnbd_migration/test/edge_builder_test.dart
index 45fbad0..0959499 100644
--- a/pkg/nnbd_migration/test/edge_builder_test.dart
+++ b/pkg/nnbd_migration/test/edge_builder_test.dart
@@ -189,6 +189,7 @@
     assertNoEdge(t.typeArguments[0].node, anyNode);
   }
 
+  @failingTest
   test_generic_to_generic_downcast() {
     var t1 = list(list(object()));
     var t2 = myListOfList(object());
@@ -452,6 +453,7 @@
     var tType = decoratedTypeAnnotation('T f');
     assertEdge(parameterType.node, tType.node, hard: true);
     assertNoEdge(parameterType.node, boundType.node);
+    // TODO(mfairhurst): Confirm we want this edge.
     assertEdge(
         parameterType.typeArguments[0].node, boundType.typeArguments[0].node,
         hard: false);
@@ -639,7 +641,9 @@
     assertNullCheck(checkExpression('(y += z)'), fReturnEdge);
   }
 
+  @failingTest
   test_assignmentExpression_compound_withSubstitution() async {
+    // Failing due to a side-cast from incorrectly instantiating the operator.
     var code = '''
 abstract class C<T> {
   C<T> operator+(C<T> x);
@@ -802,9 +806,11 @@
 List<int> f(List<int> x, List<int> y) => x ??= y;
 ''');
     var xNullable = decoratedTypeAnnotation('List<int> x').node;
+    var yNullable = decoratedTypeAnnotation('List<int> y').node;
     var xElementNullable = decoratedTypeAnnotation('int> x').node;
     var yElementNullable = decoratedTypeAnnotation('int> y').node;
     var returnElementNullable = decoratedTypeAnnotation('int> f').node;
+    assertEdge(yNullable, xNullable, hard: false, guards: [xNullable]);
     assertEdge(yElementNullable, xElementNullable,
         hard: false, guards: [xNullable]);
     assertEdge(xElementNullable, returnElementNullable, hard: false);
@@ -818,7 +824,7 @@
     var xNullable = decoratedTypeAnnotation('int x').node;
     var returnNullable = decoratedTypeAnnotation('int f').node;
     var glbNode = decoratedExpressionType('(x ??= y)').node;
-    assertEdge(yNullable, xNullable, hard: true, guards: [xNullable]);
+    assertEdge(yNullable, xNullable, hard: false, guards: [xNullable]);
     assertEdge(yNullable, glbNode, hard: false, guards: [xNullable]);
     assertEdge(glbNode, xNullable, hard: false);
     assertEdge(glbNode, yNullable, hard: false);
diff --git a/pkg/vm/bin/kernel_service.dart b/pkg/vm/bin/kernel_service.dart
index 3021d8e..39781dc 100644
--- a/pkg/vm/bin/kernel_service.dart
+++ b/pkg/vm/bin/kernel_service.dart
@@ -74,6 +74,7 @@
 bool allowDartInternalImport = false;
 
 abstract class Compiler {
+  final int isolateId;
   final FileSystem fileSystem;
   final Uri platformKernelPath;
   final bool suppressWarnings;
@@ -91,7 +92,7 @@
 
   CompilerOptions options;
 
-  Compiler(this.fileSystem, this.platformKernelPath,
+  Compiler(this.isolateId, this.fileSystem, this.platformKernelPath,
       {this.suppressWarnings: false,
       this.enableAsserts: false,
       this.experimentalFlags: null,
@@ -162,6 +163,12 @@
       CompilerResult compilerResult = await compileInternal(script);
       Component component = compilerResult.component;
 
+      if (errors.isEmpty) {
+        // Record dependencies only if compilation was error free, and before
+        // createFreshComponentWithBytecode drops the uriToSource table.
+        _recordDependencies(isolateId, component, options.packagesFileUri);
+      }
+
       if (options.bytecode && errors.isEmpty) {
         await runWithFrontEndCompilerContext(script, options, component, () {
           // TODO(alexmarkov): disable local variables info,
@@ -250,13 +257,14 @@
 class IncrementalCompilerWrapper extends Compiler {
   IncrementalCompiler generator;
 
-  IncrementalCompilerWrapper(FileSystem fileSystem, Uri platformKernelPath,
+  IncrementalCompilerWrapper(
+      int isolateId, FileSystem fileSystem, Uri platformKernelPath,
       {bool suppressWarnings: false,
       bool enableAsserts: false,
       List<String> experimentalFlags: null,
       bool bytecode: false,
       String packageConfig: null})
-      : super(fileSystem, platformKernelPath,
+      : super(isolateId, fileSystem, platformKernelPath,
             suppressWarnings: suppressWarnings,
             enableAsserts: enableAsserts,
             experimentalFlags: experimentalFlags,
@@ -281,7 +289,7 @@
 
   Future<IncrementalCompilerWrapper> clone(int isolateId) async {
     IncrementalCompilerWrapper clone = IncrementalCompilerWrapper(
-        fileSystem, platformKernelPath,
+        isolateId, fileSystem, platformKernelPath,
         suppressWarnings: suppressWarnings,
         enableAsserts: enableAsserts,
         experimentalFlags: experimentalFlags,
@@ -309,14 +317,15 @@
 class SingleShotCompilerWrapper extends Compiler {
   final bool requireMain;
 
-  SingleShotCompilerWrapper(FileSystem fileSystem, Uri platformKernelPath,
+  SingleShotCompilerWrapper(
+      int isolateId, FileSystem fileSystem, Uri platformKernelPath,
       {this.requireMain: false,
       bool suppressWarnings: false,
       bool enableAsserts: false,
       List<String> experimentalFlags: null,
       bool bytecode: false,
       String packageConfig: null})
-      : super(fileSystem, platformKernelPath,
+      : super(isolateId, fileSystem, platformKernelPath,
             suppressWarnings: suppressWarnings,
             enableAsserts: enableAsserts,
             experimentalFlags: experimentalFlags,
@@ -373,7 +382,8 @@
       // destroyed when corresponding isolate is shut down. To achieve that kernel
       // isolate needs to receive a message indicating that particular
       // isolate was shut down. Message should be handled here in this script.
-      compiler = new IncrementalCompilerWrapper(fileSystem, platformKernelPath,
+      compiler = new IncrementalCompilerWrapper(
+          isolateId, fileSystem, platformKernelPath,
           suppressWarnings: suppressWarnings,
           enableAsserts: enableAsserts,
           experimentalFlags: experimentalFlags,
@@ -476,7 +486,7 @@
 }
 
 void _recordDependencies(
-    int isolateId, Component component, String packageConfig) {
+    int isolateId, Component component, Uri packageConfig) {
   final dependencies = isolateDependencies[isolateId] ??= new List<Uri>();
 
   if (component != null) {
@@ -497,7 +507,7 @@
   }
 
   if (packageConfig != null) {
-    dependencies.add(Uri.parse(packageConfig));
+    dependencies.add(packageConfig);
   }
 }
 
@@ -653,7 +663,8 @@
   } else {
     FileSystem fileSystem = _buildFileSystem(
         sourceFiles, platformKernel, multirootFilepaths, multirootScheme);
-    compiler = new SingleShotCompilerWrapper(fileSystem, platformKernelPath,
+    compiler = new SingleShotCompilerWrapper(
+        isolateId, fileSystem, platformKernelPath,
         requireMain: false,
         suppressWarnings: suppressWarnings,
         enableAsserts: enableAsserts,
@@ -678,8 +689,6 @@
         result = new CompilationResult.errors(compiler.errors, null);
       }
     } else {
-      // Record dependencies only if compilation was error free.
-      _recordDependencies(isolateId, component, packageConfig);
       // We serialize the component excluding vm_platform.dill because the VM has
       // these sources built-in. Everything loaded as a summary in
       // [kernelForProgram] is marked `external`, so we can use that bit to
diff --git a/pkg/vm/lib/bytecode/dbc.dart b/pkg/vm/lib/bytecode/dbc.dart
index 6005219..f14f6fec 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 = 21;
+const int currentBytecodeFormatVersion = 22;
 
 enum Opcode {
   kUnusedOpcode000,
diff --git a/pkg/vm/lib/bytecode/declarations.dart b/pkg/vm/lib/bytecode/declarations.dart
index a84a607..7dba88e 100644
--- a/pkg/vm/lib/bytecode/declarations.dart
+++ b/pkg/vm/lib/bytecode/declarations.dart
@@ -332,6 +332,7 @@
   static const hasPragmaFlag = 1 << 11;
   static const hasCustomScriptFlag = 1 << 12;
   static const hasInitializerCodeFlag = 1 << 13;
+  static const hasAttributesFlag = 1 << 14;
 
   final int flags;
   final ObjectHandle name;
@@ -344,6 +345,7 @@
   final ObjectHandle setterName;
   final Code initializerCode;
   final AnnotationsDeclaration annotations;
+  final ObjectHandle attributes;
 
   FieldDeclaration(
       this.flags,
@@ -356,7 +358,8 @@
       this.getterName,
       this.setterName,
       this.initializerCode,
-      this.annotations);
+      this.annotations,
+      this.attributes);
 
   void write(BufferedWriter writer) {
     writer.writePackedUInt30(flags);
@@ -385,6 +388,9 @@
     if ((flags & hasAnnotationsFlag) != 0) {
       writer.writeLinkOffset(annotations);
     }
+    if ((flags & hasAttributesFlag) != 0) {
+      writer.writePackedObject(attributes);
+    }
   }
 
   factory FieldDeclaration.read(BufferedReader reader) {
@@ -411,8 +417,21 @@
     final annotations = ((flags & hasAnnotationsFlag) != 0)
         ? reader.readLinkOffset<AnnotationsDeclaration>()
         : null;
-    return new FieldDeclaration(flags, name, type, value, script, position,
-        endPosition, getterName, setterName, initializerCode, annotations);
+    final attributes =
+        ((flags & hasAttributesFlag) != 0) ? reader.readPackedObject() : null;
+    return new FieldDeclaration(
+        flags,
+        name,
+        type,
+        value,
+        script,
+        position,
+        endPosition,
+        getterName,
+        setterName,
+        initializerCode,
+        annotations,
+        attributes);
   }
 
   @override
@@ -456,6 +475,9 @@
     if ((flags & hasAnnotationsFlag) != 0) {
       sb.write('    annotations $annotations\n');
     }
+    if ((flags & hasAttributesFlag) != 0) {
+      sb.write('    attributes $attributes\n');
+    }
     return sb.toString();
   }
 }
@@ -484,6 +506,7 @@
   static const hasAnnotationsFlag = 1 << 20;
   static const hasPragmaFlag = 1 << 21;
   static const hasCustomScriptFlag = 1 << 22;
+  static const hasAttributesFlag = 1 << 23;
 
   final int flags;
   final ObjectHandle name;
@@ -497,6 +520,7 @@
   final ObjectHandle nativeName;
   final Code code;
   final AnnotationsDeclaration annotations;
+  final ObjectHandle attributes;
 
   FunctionDeclaration(
       this.flags,
@@ -510,7 +534,8 @@
       this.returnType,
       this.nativeName,
       this.code,
-      this.annotations);
+      this.annotations,
+      this.attributes);
 
   void write(BufferedWriter writer) {
     writer.writePackedUInt30(flags);
@@ -543,6 +568,9 @@
     if ((flags & hasAnnotationsFlag) != 0) {
       writer.writeLinkOffset(annotations);
     }
+    if ((flags & hasAttributesFlag) != 0) {
+      writer.writePackedObject(attributes);
+    }
   }
 
   factory FunctionDeclaration.read(BufferedReader reader) {
@@ -578,6 +606,8 @@
     final annotations = ((flags & hasAnnotationsFlag) != 0)
         ? reader.readLinkOffset<AnnotationsDeclaration>()
         : null;
+    final attributes =
+        ((flags & hasAttributesFlag) != 0) ? reader.readPackedObject() : null;
     return new FunctionDeclaration(
         flags,
         name,
@@ -590,7 +620,8 @@
         returnType,
         nativeName,
         code,
-        annotations);
+        annotations,
+        attributes);
   }
 
   @override
@@ -669,6 +700,9 @@
     if ((flags & hasAnnotationsFlag) != 0) {
       sb.write('    annotations $annotations\n');
     }
+    if ((flags & hasAttributesFlag) != 0) {
+      sb.write('    attributes $attributes\n');
+    }
     if ((flags & isAbstractFlag) == 0 && (flags & isExternalFlag) == 0) {
       sb.write('\n$code\n');
     }
diff --git a/pkg/vm/lib/bytecode/gen_bytecode.dart b/pkg/vm/lib/bytecode/gen_bytecode.dart
index 9f80ff9..6b64e85 100644
--- a/pkg/vm/lib/bytecode/gen_bytecode.dart
+++ b/pkg/vm/lib/bytecode/gen_bytecode.dart
@@ -56,6 +56,10 @@
 import '../metadata/bytecode.dart';
 import '../metadata/direct_call.dart'
     show DirectCallMetadata, DirectCallMetadataRepository;
+import '../metadata/inferred_type.dart'
+    show InferredType, InferredTypeMetadataRepository;
+import '../metadata/procedure_attributes.dart'
+    show ProcedureAttributesMetadata, ProcedureAttributesMetadataRepository;
 
 import 'dart:convert' show utf8;
 import 'dart:developer';
@@ -122,6 +126,10 @@
   Component bytecodeComponent;
   NullabilityDetector nullabilityDetector;
   Map<TreeNode, DirectCallMetadata> directCallMetadata;
+  ProcedureAttributesMetadataRepository procedureAttributesMetadataRepository;
+  ProcedureAttributesMetadata procedureAttributesMetadata;
+  Map<TreeNode, InferredType> inferredTypeMetadata;
+  List<Constant> inferredTypesAttribute;
 
   List<ClassDeclaration> classDeclarations;
   List<FieldDeclaration> fieldDeclarations;
@@ -175,6 +183,12 @@
 
     directCallMetadata =
         component.metadata[DirectCallMetadataRepository.repositoryTag]?.mapping;
+
+    procedureAttributesMetadataRepository =
+        component.metadata[ProcedureAttributesMetadataRepository.repositoryTag];
+
+    inferredTypeMetadata = component
+        .metadata[InferredTypeMetadataRepository.repositoryTag]?.mapping;
   }
 
   @override
@@ -402,6 +416,26 @@
     return new Annotations(decl, hasPragma);
   }
 
+  ObjectHandle getMemberAttributes(Member member) {
+    if (procedureAttributesMetadata == null && inferredTypesAttribute == null) {
+      return null;
+    }
+    // List of pairs (tag, value).
+    final attrs = <Constant>[];
+    if (procedureAttributesMetadata != null) {
+      final attribute = procedureAttributesMetadataRepository
+          .getBytecodeAttribute(procedureAttributesMetadata);
+      attrs.add(
+          StringConstant(ProcedureAttributesMetadataRepository.repositoryTag));
+      attrs.add(attribute);
+    }
+    if (inferredTypesAttribute != null) {
+      attrs.add(StringConstant(InferredTypeMetadataRepository.repositoryTag));
+      attrs.add(ListConstant(const DynamicType(), inferredTypesAttribute));
+    }
+    return objectTable.getHandle(ListConstant(const DynamicType(), attrs));
+  }
+
   // Insert annotations for the function and its parameters into the annotations
   // section. Return the annotations for the function only. The bytecode reader
   // will implicitly find the parameter annotations by reading N packed objects
@@ -564,6 +598,10 @@
         flags |= FieldDeclaration.hasPragmaFlag;
       }
     }
+    final ObjectHandle attributes = getMemberAttributes(field);
+    if (attributes != null) {
+      flags |= FieldDeclaration.hasAttributesFlag;
+    }
     ObjectHandle script;
     if (field.fileUri != null &&
         field.fileUri != (field.parent as FileUriNode).fileUri) {
@@ -583,7 +621,8 @@
         getterName,
         setterName,
         initializer,
-        annotations.object);
+        annotations.object,
+        attributes);
   }
 
   FunctionDeclaration getFunctionDeclaration(Member member, Code code) {
@@ -665,13 +704,17 @@
       position = (member as dynamic).startFileOffset;
       endPosition = member.fileEndOffset;
     }
-    Annotations annotations = getFunctionAnnotations(member);
+    final Annotations annotations = getFunctionAnnotations(member);
     if (annotations.object != null) {
       flags |= FunctionDeclaration.hasAnnotationsFlag;
       if (annotations.hasPragma) {
         flags |= FunctionDeclaration.hasPragmaFlag;
       }
     }
+    final ObjectHandle attributes = getMemberAttributes(member);
+    if (attributes != null) {
+      flags |= FunctionDeclaration.hasAttributesFlag;
+    }
     ObjectHandle script;
     if (member.fileUri != null &&
         member.fileUri != (member.parent as FileUriNode).fileUri) {
@@ -706,7 +749,8 @@
         objectTable.getHandle(function.returnType),
         nativeName,
         code,
-        annotations.object);
+        annotations.object,
+        attributes);
   }
 
   bool isReflectable(Member member) {
@@ -1133,9 +1177,12 @@
         parentFunction != null &&
         (parentFunction.dartAsyncMarker == AsyncMarker.Async ||
             parentFunction.dartAsyncMarker == AsyncMarker.AsyncStar)) {
+      final savedSourcePosition = asm.currentSourcePosition;
+      _recordSourcePosition(TreeNode.noOffset);
       _genDirectCall(
           clearAsyncThreadStackTrace, objectTable.getArgDescHandle(0), 0);
       asm.emitDrop1();
+      asm.currentSourcePosition = savedSourcePosition;
     }
 
     asm.emitReturnTOS();
@@ -1146,7 +1193,7 @@
       bool isSet: false,
       bool isDynamicForwarder: false,
       bool isUnchecked: false,
-      TreeNode context}) {
+      TreeNode node}) {
     assert(!isGet || !isSet);
     final kind = isGet
         ? InvocationKind.getter
@@ -1154,7 +1201,10 @@
     final cpIndex = cp.addDirectCall(kind, target, argDesc, isDynamicForwarder);
 
     if (totalArgCount >= argumentsLimit) {
-      throw new TooManyArgumentsException(context.fileOffset);
+      throw new TooManyArgumentsException(node.fileOffset);
+    }
+    if (inferredTypeMetadata != null && node != null) {
+      _appendInferredType(node, asm.offset);
     }
     if (isUnchecked) {
       asm.emitUncheckedDirectCall(cpIndex, totalArgCount);
@@ -1167,7 +1217,7 @@
       {bool hasReceiver: false,
       bool isFactory: false,
       bool isUnchecked: false,
-      TreeNode context}) {
+      TreeNode node}) {
     final argDesc = objectTable.getArgDescHandleByArguments(args,
         hasReceiver: hasReceiver, isFactory: isFactory);
 
@@ -1182,7 +1232,7 @@
     }
 
     _genDirectCall(target, argDesc, totalArgCount,
-        isUnchecked: isUnchecked, context: context);
+        isUnchecked: isUnchecked, node: node);
   }
 
   void _genTypeArguments(List<DartType> typeArgs, {Class instantiatingClass}) {
@@ -1516,6 +1566,31 @@
           new List<TypeParameter>.from(enclosingFunction.typeParameters);
       functionTypeParametersSet = functionTypeParameters.toSet();
     }
+    procedureAttributesMetadata = procedureAttributesMetadataRepository != null
+        ? procedureAttributesMetadataRepository.mapping[node]
+        : null;
+
+    if (inferredTypeMetadata != null) {
+      if (node is Field) {
+        // Field type is at PC = -1.
+        _appendInferredType(node, -1);
+      } else if (enclosingFunction != null && hasCode) {
+        assert(node is Procedure || node is Constructor);
+        // Parameter types are at PC = -N,..,-1 where N - number of declared
+        // (explicit) parameters.
+        int i = -(enclosingFunction.positionalParameters.length +
+            enclosingFunction.namedParameters.length);
+        for (var v in enclosingFunction.positionalParameters) {
+          _appendInferredType(v, i);
+          ++i;
+        }
+        for (var v in enclosingFunction.namedParameters) {
+          _appendInferredType(v, i);
+          ++i;
+        }
+      }
+    }
+
     if (!hasCode) {
       return;
     }
@@ -1559,6 +1634,32 @@
     _genEqualsOperatorNullHandling(node);
   }
 
+  void _appendInferredType(TreeNode node, int pc) {
+    final InferredType md = inferredTypeMetadata[node];
+    if (md == null) {
+      return;
+    }
+    inferredTypesAttribute ??= <Constant>[];
+    // List of triplets (PC, concreteClass, flags).
+    // Verify that PCs are monotonically increasing.
+    assert(inferredTypesAttribute.isEmpty ||
+        (inferredTypesAttribute[inferredTypesAttribute.length - 3]
+                    as IntConstant)
+                .value <
+            pc);
+    inferredTypesAttribute.add(IntConstant(pc));
+    Class concreteClass = md.concreteClass;
+    // VM uses more specific function type and doesn't expect to
+    // see inferred _Closure class.
+    if (concreteClass != null && concreteClass != closureClass) {
+      inferredTypesAttribute
+          .add(TypeLiteralConstant(coreTypes.legacyRawType(concreteClass)));
+    } else {
+      inferredTypesAttribute.add(NullConstant());
+    }
+    inferredTypesAttribute.add(IntConstant(md.flags));
+  }
+
   // Generate additional code for 'operator ==' to handle nulls.
   void _genEqualsOperatorNullHandling(Member member) {
     if (member.name.name != '==' ||
@@ -1655,6 +1756,9 @@
     asm = null;
     savedAssemblers = null;
     hasErrors = false;
+    procedureAttributesMetadata = null;
+    inferredTypeMetadata = null;
+    inferredTypesAttribute = null;
   }
 
   SourcePositions finalizeSourcePositions() {
@@ -1907,10 +2011,16 @@
         initializedPosition);
   }
 
-  // TODO(alexmarkov): Revise if we need to AOT-compile from bytecode.
   bool get canSkipTypeChecksForNonCovariantArguments =>
       !isClosure && enclosingMember.name.name != 'call';
 
+  bool get skipTypeChecksForGenericCovariantImplArguments =>
+      procedureAttributesMetadata != null &&
+      !procedureAttributesMetadata.hasNonThisUses &&
+      // TODO(alexmarkov): fix building of flow graph for implicit closures so
+      // it would include missing checks and remove this condition.
+      !procedureAttributesMetadata.hasTearOffUses;
+
   Member _getForwardingStubSuperTarget() {
     if (!isClosure) {
       final member = enclosingMember;
@@ -2075,7 +2185,8 @@
   bool _typeParameterNeedsBoundCheck(TypeParameter typeParam,
       Map<TypeParameter, DartType> forwardingTypeParameterBounds) {
     if (canSkipTypeChecksForNonCovariantArguments &&
-        !typeParam.isGenericCovariantImpl) {
+        (!typeParam.isGenericCovariantImpl ||
+            skipTypeChecksForGenericCovariantImplArguments)) {
       return false;
     }
     final DartType bound = (forwardingTypeParameterBounds != null)
@@ -2092,7 +2203,8 @@
       Map<VariableDeclaration, DartType> forwardingParameterTypes) {
     if (canSkipTypeChecksForNonCovariantArguments &&
         !param.isCovariant &&
-        !param.isGenericCovariantImpl) {
+        (!param.isGenericCovariantImpl ||
+            skipTypeChecksForGenericCovariantImplArguments)) {
       return false;
     }
     final DartType type = (forwardingParameterTypes != null)
@@ -2721,7 +2833,7 @@
         new Arguments(node.arguments.positional, named: node.arguments.named)
           ..parent = node;
     _genArguments(null, args);
-    _genDirectCallWithArgs(node.target, args, hasReceiver: true, context: node);
+    _genDirectCallWithArgs(node.target, args, hasReceiver: true, node: node);
     asm.emitDrop1();
   }
 
@@ -2731,7 +2843,7 @@
     _genArguments(node.receiver, args);
     final target = node.target;
     if (target is Procedure && !target.isGetter && !target.isSetter) {
-      _genDirectCallWithArgs(target, args, hasReceiver: true, context: node);
+      _genDirectCallWithArgs(target, args, hasReceiver: true, node: node);
     } else {
       throw new UnsupportedOperationError(
           'Unsupported DirectMethodInvocation with target ${target.runtimeType} $target');
@@ -2743,7 +2855,8 @@
     _generateNode(node.receiver);
     final target = node.target;
     if (target is Field || (target is Procedure && target.isGetter)) {
-      _genDirectCall(target, objectTable.getArgDescHandle(1), 1, isGet: true);
+      _genDirectCall(target, objectTable.getArgDescHandle(1), 1,
+          isGet: true, node: node);
     } else {
       throw new UnsupportedOperationError(
           'Unsupported DirectPropertyGet with ${target.runtimeType} $target');
@@ -2764,7 +2877,8 @@
 
     final target = node.target;
     assert(target is Field || (target is Procedure && target.isSetter));
-    _genDirectCall(target, objectTable.getArgDescHandle(2), 2, isSet: true);
+    _genDirectCall(target, objectTable.getArgDescHandle(2), 2,
+        isSet: true, node: node);
     asm.emitDrop1();
 
     if (hasResult) {
@@ -2985,7 +3099,14 @@
     asm.emitSpecializedBytecode(opcode);
   }
 
+  bool _isUncheckedCall(
+          Node node, Member interfaceTarget, Expression receiver) =>
+      isUncheckedCall(interfaceTarget, receiver, typeEnvironment) ||
+      (inferredTypeMetadata != null &&
+          inferredTypeMetadata[node]?.skipCheck == true);
+
   void _genInstanceCall(
+      Node node,
       InvocationKind invocationKind,
       Member interfaceTarget,
       Name targetName,
@@ -2994,7 +3115,11 @@
       ObjectHandle argDesc) {
     final isDynamic = interfaceTarget == null;
     final isUnchecked = invocationKind != InvocationKind.getter &&
-        isUncheckedCall(interfaceTarget, receiver, typeEnvironment);
+        _isUncheckedCall(node, interfaceTarget, receiver);
+
+    if (inferredTypeMetadata != null) {
+      _appendInferredType(node, asm.offset);
+    }
 
     if (invocationKind != InvocationKind.getter && !isDynamic && !isUnchecked) {
       final staticReceiverType = getStaticType(receiver, typeEnvironment);
@@ -3072,11 +3197,13 @@
     if (directCall != null) {
       final isDynamicForwarder = (interfaceTarget == null);
       final isUnchecked =
-          isUncheckedCall(interfaceTarget, node.receiver, typeEnvironment);
+          _isUncheckedCall(node, interfaceTarget, node.receiver);
       _genDirectCall(directCall.target, argDesc, totalArgCount,
-          isDynamicForwarder: isDynamicForwarder, isUnchecked: isUnchecked);
+          isDynamicForwarder: isDynamicForwarder,
+          isUnchecked: isUnchecked,
+          node: node);
     } else {
-      _genInstanceCall(InvocationKind.method, interfaceTarget, node.name,
+      _genInstanceCall(node, InvocationKind.method, interfaceTarget, node.name,
           node.receiver, totalArgCount, argDesc);
     }
   }
@@ -3096,10 +3223,10 @@
         asm.emitCheckReceiverForNull(
             cp.addSelectorName(node.name, InvocationKind.getter));
       }
-      _genDirectCall(directCall.target, argDesc, 1, isGet: true);
+      _genDirectCall(directCall.target, argDesc, 1, isGet: true, node: node);
     } else {
-      _genInstanceCall(InvocationKind.getter, node.interfaceTarget, node.name,
-          node.receiver, 1, argDesc);
+      _genInstanceCall(node, InvocationKind.getter, node.interfaceTarget,
+          node.name, node.receiver, 1, argDesc);
     }
   }
 
@@ -3132,14 +3259,15 @@
     if (directCall != null) {
       final isDynamicForwarder = (node.interfaceTarget == null);
       final isUnchecked =
-          isUncheckedCall(node.interfaceTarget, node.receiver, typeEnvironment);
+          _isUncheckedCall(node, node.interfaceTarget, node.receiver);
       _genDirectCall(directCall.target, argDesc, numArguments,
           isSet: true,
           isDynamicForwarder: isDynamicForwarder,
-          isUnchecked: isUnchecked);
+          isUnchecked: isUnchecked,
+          node: node);
     } else {
-      _genInstanceCall(InvocationKind.setter, node.interfaceTarget, node.name,
-          node.receiver, numArguments, argDesc);
+      _genInstanceCall(node, InvocationKind.setter, node.interfaceTarget,
+          node.name, node.receiver, numArguments, argDesc);
     }
 
     asm.emitDrop1();
@@ -3168,7 +3296,7 @@
     }
     _genArguments(new ThisExpression(), args);
     _genDirectCallWithArgs(target, args,
-        hasReceiver: true, isUnchecked: true, context: node);
+        hasReceiver: true, isUnchecked: true, node: node);
   }
 
   @override
@@ -3182,7 +3310,8 @@
       return;
     }
     _genPushReceiver();
-    _genDirectCall(target, objectTable.getArgDescHandle(1), 1, isGet: true);
+    _genDirectCall(target, objectTable.getArgDescHandle(1), 1,
+        isGet: true, node: node);
   }
 
   @override
@@ -3206,7 +3335,7 @@
 
       assert(target is Field || (target is Procedure && target.isSetter));
       _genDirectCall(target, objectTable.getArgDescHandle(2), 2,
-          isSet: true, isUnchecked: true);
+          isSet: true, isUnchecked: true, node: node);
     }
 
     asm.emitDrop1();
@@ -3275,11 +3404,13 @@
       } else if (_hasTrivialInitializer(target)) {
         asm.emitLoadStatic(cp.addStaticField(target));
       } else {
-        _genDirectCall(target, objectTable.getArgDescHandle(0), 0, isGet: true);
+        _genDirectCall(target, objectTable.getArgDescHandle(0), 0,
+            isGet: true, node: node);
       }
     } else if (target is Procedure) {
       if (target.isGetter) {
-        _genDirectCall(target, objectTable.getArgDescHandle(0), 0, isGet: true);
+        _genDirectCall(target, objectTable.getArgDescHandle(0), 0,
+            isGet: true, node: node);
       } else if (target.isFactory || target.isRedirectingFactoryConstructor) {
         throw 'Unexpected target for StaticGet: factory $target';
       } else {
@@ -3321,7 +3452,7 @@
     }
     _genArguments(null, args);
     _genDirectCallWithArgs(target, args,
-        isFactory: target.isFactory, context: node);
+        isFactory: target.isFactory, node: node);
   }
 
   @override
@@ -3343,7 +3474,8 @@
       int cpIndex = cp.addStaticField(target);
       asm.emitStoreStaticTOS(cpIndex);
     } else {
-      _genDirectCall(target, objectTable.getArgDescHandle(1), 1, isSet: true);
+      _genDirectCall(target, objectTable.getArgDescHandle(1), 1,
+          isSet: true, node: node);
       asm.emitDrop1();
     }
   }
@@ -4196,7 +4328,7 @@
     final args = node.arguments;
     assert(args.types.isEmpty);
     _genArguments(new ThisExpression(), args);
-    _genDirectCallWithArgs(node.target, args, hasReceiver: true, context: node);
+    _genDirectCallWithArgs(node.target, args, hasReceiver: true, node: node);
     asm.emitDrop1();
   }
 
@@ -4214,7 +4346,7 @@
       }
     }
     assert(target != null);
-    _genDirectCallWithArgs(target, args, hasReceiver: true, context: node);
+    _genDirectCallWithArgs(target, args, hasReceiver: true, node: node);
     asm.emitDrop1();
   }
 
diff --git a/pkg/vm/lib/bytecode/local_vars.dart b/pkg/vm/lib/bytecode/local_vars.dart
index 6421694..884c149 100644
--- a/pkg/vm/lib/bytecode/local_vars.dart
+++ b/pkg/vm/lib/bytecode/local_vars.dart
@@ -4,7 +4,7 @@
 
 library vm.bytecode.local_vars;
 
-import 'dart:math' show max;
+import 'dart:math' show min, max;
 
 import 'package:kernel/ast.dart';
 import 'package:kernel/transformations/continuation.dart'
@@ -848,10 +848,8 @@
 
       if (_currentScope.contextOwner == _currentScope) {
         _currentScope.contextLevel = parentContextLevel + 1;
-        _currentScope.contextId = _contextIdCounter++;
-        if (_currentScope.contextId >= contextIdLimit) {
-          throw new ContextIdOverflowException();
-        }
+        int saturatedContextId = min(_contextIdCounter++, contextIdLimit - 1);
+        _currentScope.contextId = saturatedContextId;
       } else {
         _currentScope.contextLevel = _currentScope.contextOwner.contextLevel;
         _currentScope.contextId = _currentScope.contextOwner.contextId;
@@ -1292,5 +1290,3 @@
 
 class LocalVariableIndexOverflowException
     extends BytecodeLimitExceededException {}
-
-class ContextIdOverflowException extends BytecodeLimitExceededException {}
diff --git a/pkg/vm/lib/bytecode/object_table.dart b/pkg/vm/lib/bytecode/object_table.dart
index 4170bbb..5eb9122 100644
--- a/pkg/vm/lib/bytecode/object_table.dart
+++ b/pkg/vm/lib/bytecode/object_table.dart
@@ -1161,6 +1161,16 @@
   ObjectKind get kind => ObjectKind.kTypeArguments;
 
   @override
+  bool get isCacheable {
+    for (var arg in args) {
+      if (!arg.isCacheable) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  @override
   void writeContents(BufferedWriter writer) {
     writer.writePackedList(args);
   }
diff --git a/pkg/vm/lib/kernel_front_end.dart b/pkg/vm/lib/kernel_front_end.dart
index 3e2bd46..c5e5d89 100644
--- a/pkg/vm/lib/kernel_front_end.dart
+++ b/pkg/vm/lib/kernel_front_end.dart
@@ -686,10 +686,8 @@
   if (packages.containsKey(null)) {
     packages.remove(null);
   }
-  if (packages.containsKey('main')) {
-    // Make sure main package is last.
-    packages['main'] = packages.remove('main');
-  }
+  // Make sure main package is last.
+  packages['main'] = packages.remove('main') ?? const <Library>[];
 
   for (String package in packages.keys) {
     final main = component.mainMethod;
diff --git a/pkg/vm/lib/metadata/inferred_type.dart b/pkg/vm/lib/metadata/inferred_type.dart
index c22b155..432f693 100644
--- a/pkg/vm/lib/metadata/inferred_type.dart
+++ b/pkg/vm/lib/metadata/inferred_type.dart
@@ -47,6 +47,8 @@
   bool get isInt => (_flags & flagInt) != 0;
   bool get skipCheck => (_flags & flagSkipCheck) != 0;
 
+  int get flags => _flags;
+
   @override
   String toString() {
     final base =
@@ -65,8 +67,10 @@
 
 /// Repository for [InferredType].
 class InferredTypeMetadataRepository extends MetadataRepository<InferredType> {
+  static const String repositoryTag = 'vm.inferred-type.metadata';
+
   @override
-  final String tag = 'vm.inferred-type.metadata';
+  String get tag => repositoryTag;
 
   @override
   final Map<TreeNode, InferredType> mapping = <TreeNode, InferredType>{};
diff --git a/pkg/vm/lib/metadata/procedure_attributes.dart b/pkg/vm/lib/metadata/procedure_attributes.dart
index 5b9f5ce..b5619cb 100644
--- a/pkg/vm/lib/metadata/procedure_attributes.dart
+++ b/pkg/vm/lib/metadata/procedure_attributes.dart
@@ -41,16 +41,16 @@
   static const int kTearOffUsesBit = 1 << 2;
   static const int kThisUsesBit = 1 << 3;
 
+  static const repositoryTag = 'vm.procedure-attributes.metadata';
+
   @override
-  final String tag = 'vm.procedure-attributes.metadata';
+  final String tag = repositoryTag;
 
   @override
   final Map<TreeNode, ProcedureAttributesMetadata> mapping =
       <TreeNode, ProcedureAttributesMetadata>{};
 
-  @override
-  void writeToBinary(
-      ProcedureAttributesMetadata metadata, Node node, BinarySink sink) {
+  int _getFlags(ProcedureAttributesMetadata metadata) {
     int flags = 0;
     if (metadata.hasDynamicUses) {
       flags |= kDynamicUsesBit;
@@ -64,7 +64,13 @@
     if (metadata.hasTearOffUses) {
       flags |= kTearOffUsesBit;
     }
-    sink.writeByte(flags);
+    return flags;
+  }
+
+  @override
+  void writeToBinary(
+      ProcedureAttributesMetadata metadata, Node node, BinarySink sink) {
+    sink.writeByte(_getFlags(metadata));
   }
 
   @override
@@ -82,4 +88,8 @@
         hasNonThisUses: hasNonThisUses,
         hasTearOffUses: hasTearOffUses);
   }
+
+  /// Converts [metadata] into a bytecode attribute.
+  Constant getBytecodeAttribute(ProcedureAttributesMetadata metadata) =>
+      IntConstant(_getFlags(metadata));
 }
diff --git a/pkg/vm/test/bytecode/object_table_test.dart b/pkg/vm/test/bytecode/object_table_test.dart
new file mode 100644
index 0000000..75ad973
--- /dev/null
+++ b/pkg/vm/test/bytecode/object_table_test.dart
@@ -0,0 +1,119 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:kernel/ast.dart';
+import 'package:kernel/core_types.dart' show CoreTypes;
+import 'package:kernel/testing/mock_sdk_component.dart';
+import 'package:test/test.dart';
+import 'package:expect/expect.dart';
+import 'package:vm/bytecode/object_table.dart';
+
+main() {
+  Library lib1;
+  Library lib2;
+  CoreTypes coreTypes;
+  Supertype objectSupertype;
+  ObjectTable objectTable;
+
+  Class addClass(Library lib, String name,
+      [List<TypeParameter> typeParameters = const []]) {
+    Class cls = new Class(
+        name: name, supertype: objectSupertype, typeParameters: typeParameters);
+    cls.parent = lib;
+    lib.addClass(cls);
+    return cls;
+  }
+
+  setUp(() {
+    // Start with mock SDK libraries.
+    Component component = createMockSdkComponent();
+    coreTypes = new CoreTypes(component);
+    objectSupertype = coreTypes.objectClass.asThisSupertype;
+
+    // Add test libraries.
+    lib1 = new Library(Uri.parse('org-dartlang:///test1.dart'), name: 'lib1');
+    lib1.parent = component;
+    component.libraries.add(lib1);
+
+    lib2 = new Library(Uri.parse('org-dartlang:///test2.dart'), name: 'lib2');
+    lib2.parent = component;
+    component.libraries.add(lib2);
+
+    objectTable = new ObjectTable();
+  });
+
+  tearDown(() {});
+
+  test('libraries', () {
+    final h1 = objectTable.getHandle(lib1);
+    final h2 = objectTable.getHandle(lib2);
+    Expect.notEquals(h1, h2);
+    Expect.identical(h1, objectTable.getHandle(lib1));
+    Expect.identical(h2, objectTable.getHandle(lib2));
+    Expect.equals(true, h1.isCacheable);
+    Expect.equals(true, h2.isCacheable);
+    Expect.equals(false, h1.shouldBeIncludedIntoIndexTable); // 2 uses
+    Expect.identical(h1, objectTable.getHandle(lib1));
+    Expect.equals(true, h1.shouldBeIncludedIntoIndexTable); // 3 uses
+  });
+
+  test('classes', () {
+    final Class c1 = addClass(lib1, 'A');
+    final Class c2 = addClass(lib1, 'B');
+    final Class c3 = addClass(lib2, 'A');
+    final h1 = objectTable.getHandle(c1);
+    final h2 = objectTable.getHandle(c2);
+    final h3 = objectTable.getHandle(c3);
+    Expect.notEquals(h1, h2);
+    Expect.notEquals(h1, h3);
+    Expect.notEquals(h2, h3);
+    Expect.identical(h1, objectTable.getHandle(c1));
+    Expect.identical(h2, objectTable.getHandle(c2));
+    Expect.identical(h3, objectTable.getHandle(c3));
+    Expect.equals(true, h1.isCacheable);
+    Expect.equals(true, h2.isCacheable);
+    Expect.equals(true, h3.isCacheable);
+    final lib1h = objectTable.getHandle(lib1);
+    final lib2h = objectTable.getHandle(lib2);
+    Expect.equals(true, lib1h.shouldBeIncludedIntoIndexTable); // 3 uses
+    Expect.equals(false, lib2h.shouldBeIncludedIntoIndexTable); // 2 uses
+  });
+
+  test('simple-types', () {
+    final h1a = objectTable.getHandle(new InterfaceType(coreTypes.intClass));
+    final h1b = objectTable.getHandle(new InterfaceType(coreTypes.intClass));
+    final h2a = objectTable.getHandle(const DynamicType());
+    final h2b = objectTable.getHandle(new DynamicType());
+    Expect.identical(h1a, h1b);
+    Expect.identical(h2a, h2b);
+    Expect.notEquals(h1a, h2a);
+    Expect.equals(true, h1a.isCacheable);
+    Expect.equals(true, h2a.isCacheable);
+    Expect.equals(false, h1a.shouldBeIncludedIntoIndexTable); // 2 uses
+    objectTable.getHandle(new InterfaceType(
+        coreTypes.listClass, [new InterfaceType(coreTypes.intClass)]));
+    Expect.equals(true, h1a.shouldBeIncludedIntoIndexTable); // 3 uses
+  });
+
+  test('recursive-types', () {
+    final base = addClass(lib1, "Base", [new TypeParameter("T")]);
+    final derived1 = addClass(lib1, "Derived");
+    derived1.supertype = new Supertype(base, [new InterfaceType(derived1)]);
+    final derived2 = addClass(lib2, "Derived");
+    derived2.supertype = new Supertype(base, [new InterfaceType(derived2)]);
+    final h1a = objectTable.getHandle(new InterfaceType(derived1));
+    final h1b = objectTable.getHandle(new InterfaceType(derived1));
+    final h2a = objectTable.getHandle(new InterfaceType(derived2));
+    final h2b = objectTable.getHandle(new InterfaceType(derived2));
+    Expect.identical(h1a, h1b);
+    Expect.identical(h2a, h2b);
+    Expect.notEquals(h1a, h2a);
+    Expect.equals(true, h1a.isCacheable);
+    Expect.equals(true, h2a.isCacheable);
+    final typeArgs1 = (h1a as dynamic).typeArgs;
+    final typeArgs2 = (h2a as dynamic).typeArgs;
+    Expect.equals(false, typeArgs1.isCacheable);
+    Expect.equals(false, typeArgs2.isCacheable);
+  });
+}
diff --git a/pkg/vm_service/tool/dart/generate_dart.dart b/pkg/vm_service/tool/dart/generate_dart.dart
index 7a5fbbf..7949af4 100644
--- a/pkg/vm_service/tool/dart/generate_dart.dart
+++ b/pkg/vm_service/tool/dart/generate_dart.dart
@@ -104,6 +104,7 @@
   void dispose() {
     _streamSub.cancel();
     _completers.values.forEach((c) => c.completeError('disposed'));
+    _completers.clear();
     if (_disposeHandler != null) {
       _disposeHandler();
     }
diff --git a/runtime/bin/elf_loader.cc b/runtime/bin/elf_loader.cc
index b74fe3a..409e6c6 100644
--- a/runtime/bin/elf_loader.cc
+++ b/runtime/bin/elf_loader.cc
@@ -20,8 +20,9 @@
 /// Dart_CreateAppAOTSnapshotAsElf.
 class LoadedElf {
  public:
-  explicit LoadedElf(const char* filename)
-      : filename_(strdup(filename), std::free) {}
+  explicit LoadedElf(const char* filename, uint64_t elf_data_offset)
+      : filename_(strdup(filename), std::free),
+        elf_data_offset_(elf_data_offset) {}
   ~LoadedElf();
 
   /// Loads the ELF object into memory. Returns whether the load was successful.
@@ -61,6 +62,7 @@
                              const void** mapping_start);
 
   std::unique_ptr<char, decltype(std::free)*> filename_;
+  const uint64_t elf_data_offset_;
 
   // Initialized on a successful Load().
   File* file_;
@@ -119,9 +121,13 @@
     return false;
   }
 
+  CHECK_ERROR(Utils::IsAligned(elf_data_offset_, PageSize()),
+              "File offset must be page-aligned.");
+
   file_ = File::Open(/*namespc=*/nullptr, filename_.get(),
                      bin::File::FileOpenMode::kRead);
   CHECK_ERROR(file_ != nullptr, "Cannot open ELF object file.");
+  CHECK_ERROR(file_->SetPosition(elf_data_offset_), "Invalid file offset.");
 
   CHECK(ReadHeader());
   CHECK(ReadProgramTable());
@@ -262,7 +268,7 @@
 
     void* const memory_start =
         static_cast<char*>(base_->address()) + memory_offset - adjustment;
-    const uword file_start = file_offset - adjustment;
+    const uword file_start = elf_data_offset_ + file_offset - adjustment;
     const uword length = header.memory_size + adjustment;
 
     File::MapType map_type = File::kReadOnly;
@@ -321,13 +327,13 @@
     const char* name = dynamic_string_table_ + sym.name;
     const uint8_t** output = nullptr;
 
-    if (strcmp(name, kVmSnapshotDataSymbolName) == 0) {
+    if (strcmp(name, kVmSnapshotDataAsmSymbol) == 0) {
       output = vm_data;
-    } else if (strcmp(name, kVmSnapshotInstructionsSymbolName) == 0) {
+    } else if (strcmp(name, kVmSnapshotInstructionsAsmSymbol) == 0) {
       output = vm_instrs;
-    } else if (strcmp(name, kIsolateSnapshotDataSymbolName) == 0) {
+    } else if (strcmp(name, kIsolateSnapshotDataAsmSymbol) == 0) {
       output = isolate_data;
-    } else if (strcmp(name, kIsolateSnapshotInstructionsSymbolName) == 0) {
+    } else if (strcmp(name, kIsolateSnapshotInstructionsAsmSymbol) == 0) {
       output = isolate_instrs;
     }
 
@@ -350,9 +356,11 @@
 MappedMemory* LoadedElf::MapFilePiece(uword file_start,
                                       uword file_length,
                                       const void** mem_start) {
-  const uword mapping_offset = Utils::RoundDown(file_start, PageSize());
+  const uword adjustment = (elf_data_offset_ + file_start) % PageSize();
+  const uword mapping_offset = elf_data_offset_ + file_start - adjustment;
   const uword mapping_length =
-      Utils::RoundUp(file_length + file_start % PageSize(), PageSize());
+      Utils::RoundUp(elf_data_offset_ + file_start + file_length, PageSize()) -
+      mapping_offset;
   MappedMemory* const mapping =
       file_->Map(bin::File::kReadOnly, mapping_offset, mapping_length);
 
@@ -368,14 +376,15 @@
 }  // namespace bin
 }  // namespace dart
 
-DART_EXPORT void* Dart_LoadELF(const char* filename,
-                               const char** error,
-                               const uint8_t** vm_snapshot_data,
-                               const uint8_t** vm_snapshot_instrs,
-                               const uint8_t** vm_isolate_data,
-                               const uint8_t** vm_isolate_instrs) {
+DART_EXPORT Dart_LoadedElf* Dart_LoadELF(const char* filename,
+                                         uint64_t file_offset,
+                                         const char** error,
+                                         const uint8_t** vm_snapshot_data,
+                                         const uint8_t** vm_snapshot_instrs,
+                                         const uint8_t** vm_isolate_data,
+                                         const uint8_t** vm_isolate_instrs) {
   std::unique_ptr<dart::bin::elf::LoadedElf> elf(
-      new dart::bin::elf::LoadedElf(filename));
+      new dart::bin::elf::LoadedElf(filename, file_offset));
 
   if (!elf->Load() ||
       !elf->ResolveSymbols(vm_snapshot_data, vm_snapshot_instrs,
@@ -384,9 +393,9 @@
     return nullptr;
   }
 
-  return elf.release();
+  return reinterpret_cast<Dart_LoadedElf*>(elf.release());
 }
 
-DART_EXPORT void Dart_UnloadELF(void* loaded) {
+DART_EXPORT void Dart_UnloadELF(Dart_LoadedElf* loaded) {
   delete reinterpret_cast<dart::bin::elf::LoadedElf*>(loaded);
 }
diff --git a/runtime/bin/elf_loader.h b/runtime/bin/elf_loader.h
index e8243cd..3c568f0 100644
--- a/runtime/bin/elf_loader.h
+++ b/runtime/bin/elf_loader.h
@@ -7,7 +7,8 @@
 
 #include "../include/dart_api.h"
 
-typedef void* LoadedElfLibrary;
+typedef struct {
+} Dart_LoadedElf;
 
 /// Loads an ELF object in 'filename'.
 ///
@@ -15,16 +16,20 @@
 /// in Dart_UnloadELF. On error, returns 'nullptr' and sets 'error'. The error
 /// string should not be 'free'-d.
 ///
+/// `file_offset` may be non-zero to read an ELF object embedded inside another
+/// type of file.
+///
 /// Looks up the Dart snapshot symbols "_kVmSnapshotData",
 /// "_kVmSnapshotInstructions", "_kVmIsolateData" and "_kVmIsolateInstructions"
 /// into the respectively named out-parameters.
-DART_EXPORT LoadedElfLibrary Dart_LoadELF(const char* filename,
-                                          const char** error,
-                                          const uint8_t** vm_snapshot_data,
-                                          const uint8_t** vm_snapshot_instrs,
-                                          const uint8_t** vm_isolate_data,
-                                          const uint8_t** vm_isolate_instrs);
+DART_EXPORT Dart_LoadedElf* Dart_LoadELF(const char* filename,
+                                         uint64_t file_offset,
+                                         const char** error,
+                                         const uint8_t** vm_snapshot_data,
+                                         const uint8_t** vm_snapshot_instrs,
+                                         const uint8_t** vm_isolate_data,
+                                         const uint8_t** vm_isolate_instrs);
 
-DART_EXPORT void Dart_UnloadELF(LoadedElfLibrary loaded);
+DART_EXPORT void Dart_UnloadELF(Dart_LoadedElf* loaded);
 
 #endif  // RUNTIME_BIN_ELF_LOADER_H_
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index 483368c..fbc69b3 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -1082,12 +1082,13 @@
   }
   vm_options.AddArgument("--new_gen_growth_factor=4");
 
+  AppSnapshot* app_snapshot = nullptr;
+#if defined(DART_PRECOMPILED_RUNTIME)
   // If the executable binary contains the runtime together with an appended
   // snapshot, load and run that.
   // Any arguments passed to such an executable are meant for the actual
   // application so skip all Dart VM flag parsing.
-  AppSnapshot* app_snapshot =
-      Snapshot::TryReadAppendedAppSnapshotBlobs(argv[0]);
+  app_snapshot = Snapshot::TryReadAppendedAppSnapshotElf(argv[0]);
   if (app_snapshot != nullptr) {
     script_name = argv[0];
 
@@ -1098,32 +1099,33 @@
     for (int i = 1; i < argc; i++) {
       dart_options.AddArgument(argv[i]);
     }
-  } else {
-    // Parse command line arguments.
-    if (Options::ParseArguments(argc, argv, vm_run_app_snapshot, &vm_options,
-                                &script_name, &dart_options, &print_flags_seen,
-                                &verbose_debug_seen) < 0) {
-      if (Options::help_option()) {
-        Options::PrintUsage();
-        Platform::Exit(0);
-      } else if (Options::version_option()) {
-        Options::PrintVersion();
-        Platform::Exit(0);
-      } else if (print_flags_seen) {
-        // Will set the VM flags, print them out and then we exit as no
-        // script was specified on the command line.
-        char* error =
-            Dart_SetVMFlags(vm_options.count(), vm_options.arguments());
-        if (error != NULL) {
-          Syslog::PrintErr("Setting VM flags failed: %s\n", error);
-          free(error);
-          Platform::Exit(kErrorExitCode);
-        }
-        Platform::Exit(0);
-      } else {
-        Options::PrintUsage();
+  }
+#endif
+
+  // Parse command line arguments.
+  if (app_snapshot == nullptr &&
+      Options::ParseArguments(argc, argv, vm_run_app_snapshot, &vm_options,
+                              &script_name, &dart_options, &print_flags_seen,
+                              &verbose_debug_seen) < 0) {
+    if (Options::help_option()) {
+      Options::PrintUsage();
+      Platform::Exit(0);
+    } else if (Options::version_option()) {
+      Options::PrintVersion();
+      Platform::Exit(0);
+    } else if (print_flags_seen) {
+      // Will set the VM flags, print them out and then we exit as no
+      // script was specified on the command line.
+      char* error = Dart_SetVMFlags(vm_options.count(), vm_options.arguments());
+      if (error != NULL) {
+        Syslog::PrintErr("Setting VM flags failed: %s\n", error);
+        free(error);
         Platform::Exit(kErrorExitCode);
       }
+      Platform::Exit(0);
+    } else {
+      Options::PrintUsage();
+      Platform::Exit(kErrorExitCode);
     }
   }
   DartUtils::SetEnvironment(Options::environment());
diff --git a/runtime/bin/snapshot_utils.cc b/runtime/bin/snapshot_utils.cc
index aceba6c..4e554cf 100644
--- a/runtime/bin/snapshot_utils.cc
+++ b/runtime/bin/snapshot_utils.cc
@@ -158,41 +158,10 @@
   return TryReadAppSnapshotBlobs(script_name, file);
 }
 
-AppSnapshot* Snapshot::TryReadAppendedAppSnapshotBlobs(
-    const char* container_path) {
-  File* file = File::Open(NULL, container_path, File::kRead);
-  if (file == nullptr) {
-    return nullptr;
-  }
-  RefCntReleaseScope<File> rs(file);
-
-  // Check for payload appended at the end of the container file.
-  // If header is found, jump to payload offset.
-  int64_t appended_header[2];
-  if (!file->SetPosition(file->Length() - sizeof(appended_header))) {
-    return nullptr;
-  }
-  if (!file->ReadFully(&appended_header, sizeof(appended_header))) {
-    return nullptr;
-  }
-  // Length is always encoded as Little Endian.
-  const uint64_t appended_length =
-      Utils::LittleEndianToHost64(appended_header[0]);
-  if (memcmp(&appended_header[1], appjit_magic_number.bytes,
-             appjit_magic_number.length) != 0 ||
-      appended_length <= 0 || !file->SetPosition(appended_length)) {
-    return nullptr;
-  }
-
-  return TryReadAppSnapshotBlobs(container_path, file);
-}
-
 #if defined(DART_PRECOMPILED_RUNTIME)
-
-#if defined(TARGET_OS_WINDOWS) || defined(USING_SIMULATOR)
 class ElfAppSnapshot : public AppSnapshot {
  public:
-  ElfAppSnapshot(LoadedElfLibrary elf,
+  ElfAppSnapshot(Dart_LoadedElf* elf,
                  const uint8_t* vm_snapshot_data,
                  const uint8_t* vm_snapshot_instructions,
                  const uint8_t* isolate_snapshot_data,
@@ -216,13 +185,60 @@
   }
 
  private:
-  LoadedElfLibrary elf_;
+  Dart_LoadedElf* elf_;
   const uint8_t* vm_snapshot_data_;
   const uint8_t* vm_snapshot_instructions_;
   const uint8_t* isolate_snapshot_data_;
   const uint8_t* isolate_snapshot_instructions_;
 };
-#endif  // defined(TARGET_OS_WINDOWS) || defined(USING_SIMULATOR)
+
+static AppSnapshot* TryReadAppSnapshotElf(const char* script_name,
+                                          uint64_t file_offset) {
+  const char* error = nullptr;
+  const uint8_t *vm_data_buffer = nullptr, *vm_instructions_buffer = nullptr,
+                *isolate_data_buffer = nullptr,
+                *isolate_instructions_buffer = nullptr;
+  Dart_LoadedElf* handle =
+      Dart_LoadELF(script_name, file_offset, &error, &vm_data_buffer,
+                   &vm_instructions_buffer, &isolate_data_buffer,
+                   &isolate_instructions_buffer);
+  if (handle == nullptr) {
+    Syslog::PrintErr("Loading failed: %s\n", error);
+    return nullptr;
+  }
+  return new ElfAppSnapshot(handle, vm_data_buffer, vm_instructions_buffer,
+                            isolate_data_buffer, isolate_instructions_buffer);
+  return nullptr;
+}
+
+AppSnapshot* Snapshot::TryReadAppendedAppSnapshotElf(
+    const char* container_path) {
+  File* file = File::Open(NULL, container_path, File::kRead);
+  if (file == nullptr) {
+    return nullptr;
+  }
+  RefCntReleaseScope<File> rs(file);
+
+  // Check for payload appended at the end of the container file.
+  // If header is found, jump to payload offset.
+  int64_t appended_header[2];
+  if (!file->SetPosition(file->Length() - sizeof(appended_header))) {
+    return nullptr;
+  }
+  if (!file->ReadFully(&appended_header, sizeof(appended_header))) {
+    return nullptr;
+  }
+  // Length is always encoded as Little Endian.
+  const uint64_t appended_offset =
+      Utils::LittleEndianToHost64(appended_header[0]);
+  if (memcmp(&appended_header[1], appjit_magic_number.bytes,
+             appjit_magic_number.length) != 0 ||
+      appended_offset <= 0) {
+    return nullptr;
+  }
+
+  return TryReadAppSnapshotElf(container_path, appended_offset);
+}
 
 class DylibAppSnapshot : public AppSnapshot {
  public:
@@ -264,55 +280,34 @@
   }
 
   const uint8_t* vm_data_buffer = reinterpret_cast<const uint8_t*>(
-      Extensions::ResolveSymbol(library, kVmSnapshotDataSymbolName));
+      Extensions::ResolveSymbol(library, kVmSnapshotDataCSymbol));
   if (vm_data_buffer == NULL) {
-    FATAL1("Failed to resolve symbol '%s'\n", kVmSnapshotDataSymbolName);
+    FATAL1("Failed to resolve symbol '%s'\n", kVmSnapshotDataCSymbol);
   }
 
   const uint8_t* vm_instructions_buffer = reinterpret_cast<const uint8_t*>(
-      Extensions::ResolveSymbol(library, kVmSnapshotInstructionsSymbolName));
+      Extensions::ResolveSymbol(library, kVmSnapshotInstructionsCSymbol));
   if (vm_instructions_buffer == NULL) {
-    FATAL1("Failed to resolve symbol '%s'\n",
-           kVmSnapshotInstructionsSymbolName);
+    FATAL1("Failed to resolve symbol '%s'\n", kVmSnapshotInstructionsCSymbol);
   }
 
   const uint8_t* isolate_data_buffer = reinterpret_cast<const uint8_t*>(
-      Extensions::ResolveSymbol(library, kIsolateSnapshotDataSymbolName));
+      Extensions::ResolveSymbol(library, kIsolateSnapshotDataCSymbol));
   if (isolate_data_buffer == NULL) {
-    FATAL1("Failed to resolve symbol '%s'\n", kIsolateSnapshotDataSymbolName);
+    FATAL1("Failed to resolve symbol '%s'\n", kIsolateSnapshotDataCSymbol);
   }
 
-  const uint8_t* isolate_instructions_buffer =
-      reinterpret_cast<const uint8_t*>(Extensions::ResolveSymbol(
-          library, kIsolateSnapshotInstructionsSymbolName));
+  const uint8_t* isolate_instructions_buffer = reinterpret_cast<const uint8_t*>(
+      Extensions::ResolveSymbol(library, kIsolateSnapshotInstructionsCSymbol));
   if (isolate_instructions_buffer == NULL) {
     FATAL1("Failed to resolve symbol '%s'\n",
-           kIsolateSnapshotInstructionsSymbolName);
+           kIsolateSnapshotInstructionsCSymbol);
   }
 
   return new DylibAppSnapshot(library, vm_data_buffer, vm_instructions_buffer,
                               isolate_data_buffer, isolate_instructions_buffer);
 }
 
-static AppSnapshot* TryReadAppSnapshotElf(const char* script_name) {
-#if defined(TARGET_OS_WINDOWS) || defined(USING_SIMULATOR)
-  const char* error = nullptr;
-  const uint8_t *vm_data_buffer = nullptr, *vm_instructions_buffer = nullptr,
-                *isolate_data_buffer = nullptr,
-                *isolate_instructions_buffer = nullptr;
-  void* handle = Dart_LoadELF(script_name, &error, &vm_data_buffer,
-                              &vm_instructions_buffer, &isolate_data_buffer,
-                              &isolate_instructions_buffer);
-  if (handle == nullptr) {
-    Syslog::PrintErr("Loading failed: %s\n", error);
-    return nullptr;
-  }
-  return new ElfAppSnapshot(handle, vm_data_buffer, vm_instructions_buffer,
-                            isolate_data_buffer, isolate_instructions_buffer);
-#else
-  return nullptr;
-#endif
-}
 #endif  // defined(DART_PRECOMPILED_RUNTIME)
 
 AppSnapshot* Snapshot::TryReadAppSnapshot(const char* script_name) {
@@ -343,7 +338,7 @@
     return snapshot;
   }
 
-  snapshot = TryReadAppSnapshotElf(script_name);
+  snapshot = TryReadAppSnapshotElf(script_name, /*file_offset=*/0);
   if (snapshot != nullptr) {
     return snapshot;
   }
diff --git a/runtime/bin/snapshot_utils.h b/runtime/bin/snapshot_utils.h
index 5b7cf82..4fa221c 100644
--- a/runtime/bin/snapshot_utils.h
+++ b/runtime/bin/snapshot_utils.h
@@ -37,8 +37,7 @@
                                     const uint8_t* shared_instructions);
   static void GenerateAppAOTAsAssembly(const char* snapshot_filename);
 
-  static AppSnapshot* TryReadAppendedAppSnapshotBlobs(
-      const char* container_path);
+  static AppSnapshot* TryReadAppendedAppSnapshotElf(const char* container_path);
   static AppSnapshot* TryReadAppSnapshot(const char* script_name);
   static void WriteAppSnapshot(const char* filename,
                                uint8_t* vm_data_buffer,
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index d6d34c6..0306c3b 100644
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -3360,41 +3360,45 @@
                                             const uint8_t* buffer,
                                             intptr_t size);
 
+// On Darwin systems, 'dlsym' adds an '_' to the beginning of the symbol name.
+// Use the '...CSymbol' definitions for resolving through 'dlsym'. The actual
+// symbol names in the objects are given by the '...AsmSymbol' definitions.
 #if defined(__APPLE__)
-#define kVmSnapshotDataSymbolName "kDartVmSnapshotData"
-#define kVmSnapshotInstructionsSymbolName "kDartVmSnapshotInstructions"
-#define kIsolateSnapshotDataSymbolName "kDartIsolateSnapshotData"
-#define kIsolateSnapshotInstructionsSymbolName                                 \
-  "kDartIsolateSnapshotInstructions"
+#define kVmSnapshotDataCSymbol "kDartVmSnapshotData"
+#define kVmSnapshotInstructionsCSymbol "kDartVmSnapshotInstructions"
+#define kIsolateSnapshotDataCSymbol "kDartIsolateSnapshotData"
+#define kIsolateSnapshotInstructionsCSymbol "kDartIsolateSnapshotInstructions"
 #else
-#define kVmSnapshotDataSymbolName "_kDartVmSnapshotData"
-#define kVmSnapshotInstructionsSymbolName "_kDartVmSnapshotInstructions"
-#define kIsolateSnapshotDataSymbolName "_kDartIsolateSnapshotData"
-#define kIsolateSnapshotInstructionsSymbolName                                 \
-  "_kDartIsolateSnapshotInstructions"
+#define kVmSnapshotDataCSymbol "_kDartVmSnapshotData"
+#define kVmSnapshotInstructionsCSymbol "_kDartVmSnapshotInstructions"
+#define kIsolateSnapshotDataCSymbol "_kDartIsolateSnapshotData"
+#define kIsolateSnapshotInstructionsCSymbol "_kDartIsolateSnapshotInstructions"
 #endif
 
+#define kVmSnapshotDataAsmSymbol "_kDartVmSnapshotData"
+#define kVmSnapshotInstructionsAsmSymbol "_kDartVmSnapshotInstructions"
+#define kIsolateSnapshotDataAsmSymbol "_kDartIsolateSnapshotData"
+#define kIsolateSnapshotInstructionsAsmSymbol                                  \
+  "_kDartIsolateSnapshotInstructions"
+
 /**
  *  Creates a precompiled snapshot.
  *   - A root library must have been loaded.
  *   - Dart_Precompile must have been called.
  *
- *  Outputs an assembly file defining the symbols
- *   - _kDartVmSnapshotData
- *   - _kDartVmSnapshotInstructions
- *   - _kDartIsolateSnapshotData
- *   - _kDartIsolateSnapshotInstructions
+ *  Outputs an assembly file defining the symbols listed in the definitions
+ *  above.
  *
  *  The assembly should be compiled as a static or shared library and linked or
- *  loaded by the embedder.
- *  Running this snapshot requires a VM compiled with DART_PRECOMPILED_SNAPSHOT.
- *  The kDartVmSnapshotData and kDartVmSnapshotInstructions should be passed to
- *  Dart_Initialize. The kDartIsolateSnapshotData and
- *  kDartIsolateSnapshotInstructions should be passed to Dart_CreateIsolateGroup.
+ *  loaded by the embedder. Running this snapshot requires a VM compiled with
+ *  DART_PRECOMPILED_SNAPSHOT. The kDartVmSnapshotData and
+ *  kDartVmSnapshotInstructions should be passed to Dart_Initialize. The
+ *  kDartIsolateSnapshotData and kDartIsolateSnapshotInstructions should be
+ *  passed to Dart_CreateIsolateGroup.
  *
  *  The callback will be invoked one or more times to provide the assembly code.
  *
- * \return A valid handle if no error occurs during the operation.
+ *  \return A valid handle if no error occurs during the operation.
  */
 DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle
 Dart_CreateAppAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback,
diff --git a/runtime/observatory/tests/service/coverage_const_field_test.dart b/runtime/observatory/tests/service/coverage_const_field_async_closure_test.dart
similarity index 68%
rename from runtime/observatory/tests/service/coverage_const_field_test.dart
rename to runtime/observatory/tests/service/coverage_const_field_async_closure_test.dart
index 9184a23..a89b0e9 100644
--- a/runtime/observatory/tests/service/coverage_const_field_test.dart
+++ b/runtime/observatory/tests/service/coverage_const_field_async_closure_test.dart
@@ -8,13 +8,23 @@
 import 'service_test_common.dart';
 import 'test_helper.dart';
 
-const int LINE = 14;
+const int LINE_A = 15; // LINE_A - 4
+const int LINE_B = 23; // LINE_A - 3
 
 class Bar {
-  static const String field = "field"; // LINE
+  static const String field = "field"; // LINE_A
 }
 
-void testFunction() {
+Future<String> fooAsync(int x) async {
+  if (x == 42) {
+    return '*' * x;
+  }
+  return List.generate(x, (_) => 'xyzzy').join(' ');
+} // LINE_B
+
+void testFunction() async {
+  await new Future.delayed(Duration(milliseconds: 500));
+  fooAsync(42).then((_) {});
   debugger();
 }
 
@@ -26,7 +36,8 @@
     // Make sure we are in the right place.
     expect(stack.type, 'Stack');
     expect(stack['frames'].length, greaterThanOrEqualTo(1));
-    expect(stack['frames'][0].function.name, 'testFunction');
+    // Async closure of testFunction
+    expect(stack['frames'][0].function.name, 'async_op');
 
     var root = isolate.rootLibrary;
     await root.load();
@@ -49,12 +60,11 @@
           throw FormatException('token ${i} was missing source location');
         }
         // Check LINE.
-        if (line == LINE) {
-          match = (match | 1);
-        } else if (line == LINE - 3) {
-          // static const field LINE is defined at LINE - 3.
-          match = (match | 2);
+        if (line == LINE_A || line == LINE_A - 3 || line == LINE_A - 4) {
+          match = match + 1;
         }
+        // _clearAsyncThreadStackTrace should have an invalid token position.
+        expect(line, isNot(LINE_B));
       }
     }
     // Neither LINE nor Bar.field should be added into coverage.
diff --git a/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart b/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart
index 3884a9b..ada40d9 100644
--- a/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart
+++ b/runtime/observatory/tests/service/get_vm_timeline_rpc_test.dart
@@ -13,7 +13,8 @@
   Timeline.startSync('apple');
   Timeline.instantSync('ISYNC', arguments: {'fruit': 'banana'});
   Timeline.finishSync();
-  TimelineTask task = new TimelineTask();
+  TimelineTask parentTask = TimelineTask.withTaskId(42);
+  TimelineTask task = TimelineTask(parent: parentTask);
   task.start('TASK1', arguments: {'task1-start-key': 'task1-start-value'});
   task.instant('ITASK',
       arguments: {'task1-instant-key': 'task1-instant-value'});
@@ -126,8 +127,10 @@
         eventsContains(dartEvents, 'i', 'ISYNC', {'fruit': 'banana'}), isTrue);
     expect(eventsContains(dartEvents, 'X', 'apple'), isTrue);
     expect(
-        eventsContains(
-            dartEvents, 'b', 'TASK1', {'task1-start-key': 'task1-start-value'}),
+        eventsContains(dartEvents, 'b', 'TASK1', {
+          'task1-start-key': 'task1-start-value',
+          'parentId': 42.toRadixString(16)
+        }),
         isTrue);
     expect(
         eventsContains(dartEvents, 'e', 'TASK1',
diff --git a/runtime/observatory/tests/service/pause_on_unhandled_async_exceptions3_test.dart b/runtime/observatory/tests/service/pause_on_unhandled_async_exceptions3_test.dart
index 454c1c2..e46654b 100644
--- a/runtime/observatory/tests/service/pause_on_unhandled_async_exceptions3_test.dart
+++ b/runtime/observatory/tests/service/pause_on_unhandled_async_exceptions3_test.dart
@@ -10,7 +10,9 @@
 import 'test_helper.dart';
 import 'service_test_common.dart';
 
-const LINE_A = 16;
+const LINE_A = 18;
+const LINE_B = 23;
+const LINE_C = 26;
 
 throwException() async {
   throw 'exception'; // LINE_A
@@ -18,8 +20,12 @@
 
 testeeMain() async {
   try {
-    await throwException();
-  } finally {}
+    await throwException(); // LINE_B
+  } finally {
+    try {
+      await throwException(); // LINE_C
+    } finally {}
+  }
 }
 
 var tests = <IsolateTest>[
@@ -29,6 +35,26 @@
     print("Stopped!");
     var stack = await isolate.getStack();
     expect(stack['frames'][0].function.toString(), contains('throwException'));
+  },
+  resumeIsolate,
+  hasStoppedWithUnhandledException,
+  (Isolate isolate) async {
+    var stack = await isolate.getStack();
+    print(stack['frames'][0]);
+    // await in testeeMain
+    expect(await stack['frames'][0].location.toUserString(),
+        contains('.dart:${LINE_B}'));
+  },
+  resumeIsolate,
+  hasStoppedWithUnhandledException,
+  stoppedAtLine(LINE_A),
+  resumeIsolate,
+  hasStoppedWithUnhandledException,
+  (Isolate isolate) async {
+    var stack = await isolate.getStack();
+    print(stack['frames'][0]);
+    expect(await stack['frames'][0].location.toUserString(),
+        contains('.dart:${LINE_C}'));
   }
 ];
 
diff --git a/runtime/observatory/web/timeline.js b/runtime/observatory/web/timeline.js
index 56afbbbe..a9372f5 100644
--- a/runtime/observatory/web/timeline.js
+++ b/runtime/observatory/web/timeline.js
@@ -558,7 +558,7 @@
   loadingOverlay = undefined;
 }
 
-function populateTimeline(traceObject) {
+function populateTimeline() {
   updateTimeline(traceObject);
   hideLoadingOverlay();
 }
diff --git a/runtime/observatory/web/timeline_message_handler.js b/runtime/observatory/web/timeline_message_handler.js
index 2fa3e77..04925ec 100644
--- a/runtime/observatory/web/timeline_message_handler.js
+++ b/runtime/observatory/web/timeline_message_handler.js
@@ -21,11 +21,11 @@
   console.log('method: ' + method)
   switch (method) {
     case 'refresh':
+      traceObject = params;
       if (typeof populateTimeline != 'undefined') {
-        populateTimeline(params);
+        populateTimeline();
       } else {
         console.log('populateTimeline is not yet defined');
-        traceObject = params;
       }
     break;
     case 'clear':
diff --git a/runtime/tests/vm/dart/snapshot_depfile_test.dart b/runtime/tests/vm/dart/snapshot_depfile_test.dart
new file mode 100644
index 0000000..1465b17
--- /dev/null
+++ b/runtime/tests/vm/dart/snapshot_depfile_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 'dart:async';
+import 'dart:io';
+
+import 'package:expect/expect.dart';
+import 'package:path/path.dart' as p;
+
+import 'snapshot_test_helper.dart';
+
+Future<void> main(List<String> args) async {
+  if (!Platform.script.toFilePath().endsWith('.dart')) {
+    print('This test must run from source');
+    return;
+  }
+
+  await withTempDir((String temp) async {
+    final snapshotPath = p.join(temp, 'snapshot_depfile_test.snapshot');
+    final depfilePath = p.join(temp, 'snapshot_depfile_test.snapshot.d');
+
+    await runDart('GENERATE SNAPSHOT', [
+      '--snapshot=$snapshotPath',
+      '--snapshot-depfile=$depfilePath',
+      Platform.script.toFilePath(),
+      '--child',
+    ]);
+
+    var depfileContents = await new File(depfilePath).readAsString();
+    print(depfileContents);
+    Expect.isTrue(depfileContents.contains('snapshot_depfile_test.snapshot:'),
+        'depfile contains output');
+    Expect.isTrue(depfileContents.contains('snapshot_depfile_test.dart'),
+        'depfile contains input');
+  });
+}
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index d653126..231005a 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -103,6 +103,7 @@
 [ $compiler != dartk && $compiler != dartkb && $compiler != none ]
 dart/appjit*: SkipByDesign # Test needs to run from source
 dart/kernel_determinism_test: SkipByDesign # Test needs to run from source
+dart/snapshot_depfile_test: SkipByDesign # Test needs to run from source
 
 [ $compiler == dartkp && ($runtime == dart_precompiled || $runtime == vm) ]
 dart/redirection_type_shuffling_test: SkipByDesign # Includes dart:mirrors.
diff --git a/runtime/tools/dartfuzz/dartfuzz.dart b/runtime/tools/dartfuzz/dartfuzz.dart
index d09a711..0064441 100644
--- a/runtime/tools/dartfuzz/dartfuzz.dart
+++ b/runtime/tools/dartfuzz/dartfuzz.dart
@@ -14,11 +14,12 @@
 // 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.57';
+const String version = '1.59';
 
 // Restriction on statements and expressions.
 const int stmtDepth = 1;
 const int exprDepth = 2;
+const int nestDepth = 1;
 const int numStatements = 2;
 const int numGlobalVars = 4;
 const int numLocalVars = 4;
@@ -484,7 +485,6 @@
     indent -= 2;
     emitLn('} on OutOfMemoryError {');
     indent += 2;
-    emitLn("print(\'oom\');");
     emitLn("exit(${oomExitCode});");
     indent -= 2;
     emitLn('} catch (e, st) {');
@@ -622,18 +622,24 @@
   bool emitAssign() {
     // Select a type at random.
     final tp = oneOfSet(dartType.allTypes);
-    // Select one of the assign operations for the given type.
-    final assignOp = oneOfSet(dartType.assignOps(tp));
-    if (assignOp == null) {
-      throw 'No assign operation for ${tp.name}';
+    String assignOp;
+    if (DartType.isGrowableType(tp)) {
+      // Assignments like *= and += on growable types (String, List, ...)
+      // may lead to OOM, especially within loops.
+      // TODO: Implement a more specific heuristic that selectively allows
+      // modifying assignment operators (like += *=) for growable types.
+      assignOp = '=';
+    } else {
+      // Select one of the assign operations for the given type.
+      assignOp = oneOfSet(dartType.assignOps(tp));
+      if (assignOp == null) {
+        throw 'No assign operation for ${tp.name}';
+      }
     }
     emitLn('', newline: false);
     // Emit a variable of the lhs type.
     final emittedVar = emitVar(0, tp, isLhs: true);
     RhsFilter rhsFilter = RhsFilter.fromDartType(tp, emittedVar);
-    if ({'*=', '+='}.contains(assignOp)) {
-      rhsFilter?.consume();
-    }
     emit(" $assignOp ");
     // Select one of the possible rhs types for the given lhs type and assign
     // operation.
@@ -642,13 +648,7 @@
       throw 'No rhs type for assign ${tp.name} $assignOp';
     }
 
-    // We need to avoid cases of "abcde" *= large number in loops.
-    if (assignOp == "*=" && tp == DartType.STRING && rhsType == DartType.INT) {
-      emitSmallPositiveInt();
-    } else {
-      // Emit an expression for the right hand side.
-      emitExpr(0, rhsType, rhsFilter: rhsFilter);
-    }
+    emitExpr(0, rhsType, rhsFilter: rhsFilter);
     emit(';', newline: true);
     return true;
   }
@@ -714,6 +714,10 @@
 
   // Emit a simple increasing for-loop.
   bool emitFor(int depth) {
+    // Make deep nesting of loops increasingly unlikely.
+    if (rand.nextInt(nest + 1) > nestDepth) {
+      return emitAssign();
+    }
     final int i = localVars.length;
     emitLn('for (int $localName$i = 0; $localName$i < ', newline: false);
     emitSmallPositiveInt();
@@ -733,6 +737,10 @@
 
   // Emit a simple membership for-in-loop.
   bool emitForIn(int depth) {
+    // Make deep nesting of loops increasingly unlikely.
+    if (rand.nextInt(nest + 1) > nestDepth) {
+      return emitAssign();
+    }
     final int i = localVars.length;
     // Select one iterable type to be used in 'for in' statement.
     final iterType = oneOfSet(dartType.iterableTypes1);
@@ -759,6 +767,10 @@
 
   // Emit a simple membership forEach loop.
   bool emitForEach(int depth) {
+    // Make deep nesting of loops increasingly unlikely.
+    if (rand.nextInt(nest + 1) > nestDepth) {
+      return emitAssign();
+    }
     final int i = localVars.length;
     final int j = i + 1;
     emitLn("", newline: false);
@@ -786,6 +798,10 @@
 
   // Emit a while-loop.
   bool emitWhile(int depth) {
+    // Make deep nesting of loops increasingly unlikely.
+    if (rand.nextInt(nest + 1) > nestDepth) {
+      return emitAssign();
+    }
     final int i = localVars.length;
     emitLn('{ int $localName$i = ', newline: false);
     emitSmallPositiveInt();
@@ -809,6 +825,10 @@
 
   // Emit a do-while-loop.
   bool emitDoWhile(int depth) {
+    // Make deep nesting of loops increasingly unlikely.
+    if (rand.nextInt(nest + 1) > nestDepth) {
+      return emitAssign();
+    }
     final int i = localVars.length;
     emitLn('{ int $localName$i = 0;');
     indent += 2;
@@ -983,7 +1003,7 @@
     emit(rand.nextInt(2) == 0 ? 'true' : 'false');
   }
 
-  void emitSmallPositiveInt({int limit = 100}) {
+  void emitSmallPositiveInt({int limit = 50}) {
     emit('${rand.nextInt(limit)}');
   }
 
@@ -1064,13 +1084,7 @@
     if (DartType.isMapType(tp)) {
       // Emit construct for the map key type.
       final indexType = dartType.indexType(tp);
-      // This check determines whether we are emitting a global variable.
-      // I.e. whenever we are not currently emitting part of a class.
-      if (currentMethod != null) {
-        emitExpr(depth, indexType, rhsFilter: rhsFilter);
-      } else {
-        emitLiteral(depth, indexType, rhsFilter: rhsFilter);
-      }
+      emitElementExpr(depth, indexType, rhsFilter: rhsFilter);
       emit(' : ');
       // Emit construct for the map value type.
       emitElementExpr(depth, elementType, rhsFilter: rhsFilter);
diff --git a/runtime/tools/dartfuzz/dartfuzz_test.dart b/runtime/tools/dartfuzz/dartfuzz_test.dart
index 1510b3f..7a0e601 100644
--- a/runtime/tools/dartfuzz/dartfuzz_test.dart
+++ b/runtime/tools/dartfuzz/dartfuzz_test.dart
@@ -345,7 +345,10 @@
     fp = samePrecision(mode1, mode2);
     // Occasionally test FFI.
     ffi = ffiCapable(mode1, mode2) && (rand.nextInt(5) == 0);
-    flatTp = !nestedTypesAllowed(mode1, mode2) || (rand.nextInt(5) == 0);
+    // TODO (https://github.com/dart-lang/sdk/issues/38710):
+    // re-enable non-flat types once hash issue is fixed.
+    // flatTp = !nestedTypesAllowed(mode1, mode2) || (rand.nextInt(5) == 0);
+    flatTp = true;
     runner1 =
         TestRunner.getTestRunner(mode1, top, tmpDir.path, env, fileName, rand);
     runner2 =
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc
index fb472d3..1de73f8 100644
--- a/runtime/vm/compiler/aot/precompiler.cc
+++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -389,6 +389,7 @@
       I->object_store()->set_async_star_move_next_helper(null_function);
       I->object_store()->set_complete_on_async_return(null_function);
       I->object_store()->set_async_star_stream_controller(null_class);
+      I->object_store()->set_bytecode_attributes(Array::null_array());
       DropMetadata();
       DropLibraryEntries();
     }
diff --git a/runtime/vm/compiler/backend/il_arm.cc b/runtime/vm/compiler/backend/il_arm.cc
index 16371b3..348ade2 100644
--- a/runtime/vm/compiler/backend/il_arm.cc
+++ b/runtime/vm/compiler/backend/il_arm.cc
@@ -1013,7 +1013,7 @@
 
   // Reserve space for arguments and align frame before entering C++ world.
   __ ReserveAlignedFrameSpace(compiler::ffi::NumStackSlots(arg_locations_) *
-                              kWordSize);
+                              compiler::target::kWordSize);
 
   FrameRebase rebase(/*old_base=*/FPREG, /*new_base=*/saved_fp,
                      /*stack_delta=*/0);
@@ -1027,7 +1027,8 @@
   // We need to copy the return address up into the dummy stack frame so the
   // stack walker will know which safepoint to use.
   __ mov(TMP, compiler::Operand(PC));
-  __ str(TMP, compiler::Address(FPREG, kSavedCallerPcSlotFromFp * kWordSize));
+  __ str(TMP, compiler::Address(FPREG, kSavedCallerPcSlotFromFp *
+                                           compiler::target::kWordSize));
 
   // For historical reasons, the PC on ARM points 8 bytes past the current
   // instruction. Therefore we emit the metadata here, 8 bytes (2 instructions)
@@ -1063,7 +1064,8 @@
   // Restore the global object pool after returning from runtime (old space is
   // moving, so the GOP could have been relocated).
   if (FLAG_precompiled_mode && FLAG_use_bare_instructions) {
-    __ ldr(PP, compiler::Address(THR, Thread::global_object_pool_offset()));
+    __ ldr(PP, compiler::Address(
+                   THR, compiler::target::Thread::global_object_pool_offset()));
   }
 
   // Leave dummy exit frame.
@@ -1101,7 +1103,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
@@ -1164,7 +1166,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
diff --git a/runtime/vm/compiler/compiler_state.h b/runtime/vm/compiler/compiler_state.h
index be14d0b..e1a5f5c 100644
--- a/runtime/vm/compiler/compiler_state.h
+++ b/runtime/vm/compiler/compiler_state.h
@@ -98,6 +98,8 @@
   //
   // TODO(vegorov): create context classes for distinct context IDs and
   // populate them with slots without creating variables.
+  // Beware that context_id is satured at 8-bits, so multiple contexts may
+  // share id 255.
   const ZoneGrowableArray<const Slot*>& GetDummyContextSlots(
       intptr_t context_id,
       intptr_t num_context_slots);
@@ -113,6 +115,8 @@
   // same index.
   //
   // TODO(vegorov): disambiguate slots for different context IDs.
+  // Beware that context_id is satured at 8-bits, so multiple contexts may
+  // share id 255.
   LocalVariable* GetDummyCapturedVariable(intptr_t context_id, intptr_t index);
 
  private:
diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
index be09321..6edaba1 100644
--- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
+++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.cc
@@ -153,9 +153,6 @@
   if (is_generating_interpreter()) {
     UNIMPLEMENTED();  // TODO(alexmarkov): interpreter
   } else {
-    // TODO(alexmarkov): Make table of local variables in bytecode and
-    // propagate type, name and positions.
-
     ASSERT(local_vars_.is_empty());
 
     const intptr_t num_bytecode_locals = frame_size.value();
@@ -230,8 +227,23 @@
   const AbstractType& type =
       AbstractType::ZoneHandle(Z, function().ParameterTypeAt(param_index));
 
-  LocalVariable* param_var = new (Z) LocalVariable(
-      TokenPosition::kNoSource, TokenPosition::kNoSource, name, type);
+  CompileType* param_type = nullptr;
+  if (!inferred_types_attribute_.IsNull()) {
+    // Parameter types are assigned to synthetic PCs = -N,..,-1
+    // where N is number of parameters.
+    const intptr_t pc = -function().NumParameters() + param_index;
+    // Search from the beginning as parameters may be declared in arbitrary
+    // order.
+    inferred_types_index_ = 0;
+    const InferredTypeMetadata inferred_type = GetInferredType(pc);
+    if (!inferred_type.IsTrivial()) {
+      param_type = new (Z) CompileType(inferred_type.ToCompileType(Z));
+    }
+  }
+
+  LocalVariable* param_var =
+      new (Z) LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
+                            name, type, param_type);
   param_var->set_index(var_index);
 
   if (!function().IsNonImplicitClosureFunction() &&
@@ -448,6 +460,31 @@
   return arguments;
 }
 
+InferredTypeMetadata BytecodeFlowGraphBuilder::GetInferredType(intptr_t pc) {
+  ASSERT(!inferred_types_attribute_.IsNull());
+  intptr_t i = inferred_types_index_;
+  const intptr_t len = inferred_types_attribute_.Length();
+  for (; i < len; i += InferredTypeBytecodeAttribute::kNumElements) {
+    ASSERT(i + InferredTypeBytecodeAttribute::kNumElements <= len);
+    const intptr_t attr_pc =
+        InferredTypeBytecodeAttribute::GetPCAt(inferred_types_attribute_, i);
+    if (attr_pc == pc) {
+      const InferredTypeMetadata result =
+          InferredTypeBytecodeAttribute::GetInferredTypeAt(
+              Z, inferred_types_attribute_, i);
+      // Found. Next time, continue search at the next entry.
+      inferred_types_index_ = i + InferredTypeBytecodeAttribute::kNumElements;
+      return result;
+    }
+    if (attr_pc > pc) {
+      break;
+    }
+  }
+  // Not found. Next time, continue search at the last inspected entry.
+  inferred_types_index_ = i;
+  return InferredTypeMetadata(kDynamicCid, InferredTypeMetadata::kFlagNullable);
+}
+
 void BytecodeFlowGraphBuilder::PropagateStackState(intptr_t target_pc) {
   if (is_generating_interpreter() || IsStackEmpty()) {
     return;
@@ -861,7 +898,14 @@
     call->set_entry_kind(Code::EntryKind::kUnchecked);
   }
 
-  call->InitResultType(Z);
+  if (!call->InitResultType(Z)) {
+    if (!inferred_types_attribute_.IsNull()) {
+      const InferredTypeMetadata result_type = GetInferredType(pc_);
+      if (!result_type.IsTrivial()) {
+        call->SetResultType(Z, result_type.ToCompileType(Z));
+      }
+    }
+  }
 
   code_ <<= call;
   B->Push(call);
@@ -928,7 +972,12 @@
       Array::ZoneHandle(Z, arg_desc.GetArgumentNames()), checked_argument_count,
       *ic_data_array_, B->GetNextDeoptId(), interface_target);
 
-  // TODO(alexmarkov): add type info - call->SetResultType()
+  if (!inferred_types_attribute_.IsNull()) {
+    const InferredTypeMetadata result_type = GetInferredType(pc_);
+    if (!result_type.IsTrivial()) {
+      call->SetResultType(Z, result_type.ToCompileType(Z));
+    }
+  }
 
   if (is_unchecked_call) {
     call->set_entry_kind(Code::EntryKind::kUnchecked);
@@ -991,6 +1040,14 @@
       Array::ZoneHandle(Z, arg_desc.GetArgumentNames()), position_,
       B->GetNextDeoptId(), Code::EntryKind::kUnchecked);
 
+  // TODO(alexmarkov): use inferred result type for ClosureCallInstr
+  //  if (!inferred_types_attribute_.IsNull()) {
+  //    const InferredTypeMetadata result_type = GetInferredType(pc_);
+  //    if (!result_type.IsTrivial()) {
+  //      call->SetResultType(Z, result_type.ToCompileType(Z));
+  //    }
+  //  }
+
   code_ <<= call;
   B->Push(call);
 }
@@ -1025,7 +1082,12 @@
       Array::ZoneHandle(Z, arg_desc.GetArgumentNames()), checked_argument_count,
       *ic_data_array_, B->GetNextDeoptId(), interface_target);
 
-  // TODO(alexmarkov): add type info - call->SetResultType()
+  if (!inferred_types_attribute_.IsNull()) {
+    const InferredTypeMetadata result_type = GetInferredType(pc_);
+    if (!result_type.IsTrivial()) {
+      call->SetResultType(Z, result_type.ToCompileType(Z));
+    }
+  }
 
   code_ <<= call;
   B->Push(call);
@@ -2171,6 +2233,9 @@
 
   CollectControlFlow(descriptors, handlers, graph_entry_);
 
+  inferred_types_attribute_ ^= BytecodeReader::GetBytecodeAttribute(
+      function(), Symbols::vm_inferred_type_metadata());
+
   kernel::BytecodeSourcePositionsIterator source_pos_iter(Z, bytecode);
   bool update_position = source_pos_iter.MoveNext();
 
diff --git a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h
index 814b8df..6b1ea18 100644
--- a/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h
+++ b/runtime/vm/compiler/frontend/bytecode_flow_graph_builder.h
@@ -7,6 +7,7 @@
 
 #include "vm/compiler/backend/il.h"
 #include "vm/compiler/frontend/base_flow_graph_builder.h"
+#include "vm/compiler/frontend/kernel_translation_helper.h"  // For InferredTypeMetadata
 #include "vm/constants_kbc.h"
 
 #if !defined(DART_PRECOMPILED_RUNTIME)
@@ -42,7 +43,8 @@
         stacktrace_var_(nullptr),
         scratch_var_(nullptr),
         prologue_info_(-1, -1),
-        throw_no_such_method_(nullptr) {}
+        throw_no_such_method_(nullptr),
+        inferred_types_attribute_(Array::Handle(zone_)) {}
 
   FlowGraph* BuildGraph();
 
@@ -158,6 +160,7 @@
   intptr_t GetStackDepth() const;
   bool IsStackEmpty() const;
   ArgumentArray GetArguments(int count);
+  InferredTypeMetadata GetInferredType(intptr_t pc);
   void PropagateStackState(intptr_t target_pc);
   void DropUnusedValuesFromStack();
   void BuildJumpIfStrictCompare(Token::Kind cmp_kind);
@@ -236,6 +239,8 @@
   bool build_debug_step_checks_ = false;
   bool seen_parameters_scope_ = false;
   BytecodeScope* current_scope_ = nullptr;
+  Array& inferred_types_attribute_;
+  intptr_t inferred_types_index_ = 0;
 };
 
 }  // namespace kernel
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.cc b/runtime/vm/compiler/frontend/bytecode_reader.cc
index 0f3eb24..a888b26 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.cc
+++ b/runtime/vm/compiler/frontend/bytecode_reader.cc
@@ -1872,6 +1872,41 @@
   return type_arguments.Canonicalize();
 }
 
+void BytecodeReaderHelper::ReadAttributes(const Object& key) {
+  ASSERT(key.IsFunction() || key.IsField());
+  const auto& value = Object::Handle(Z, ReadObject());
+
+  Array& attributes =
+      Array::Handle(Z, I->object_store()->bytecode_attributes());
+  if (attributes.IsNull()) {
+    attributes = HashTables::New<BytecodeAttributesMap>(16, Heap::kOld);
+  }
+  BytecodeAttributesMap map(attributes.raw());
+  bool present = map.UpdateOrInsert(key, value);
+  ASSERT(!present);
+  I->object_store()->set_bytecode_attributes(map.Release());
+
+  if (key.IsField()) {
+    const Field& field = Field::Cast(key);
+    const auto& inferred_type_attr =
+        Array::CheckedHandle(Z, BytecodeReader::GetBytecodeAttribute(
+                                    key, Symbols::vm_inferred_type_metadata()));
+
+    if (!inferred_type_attr.IsNull() &&
+        (InferredTypeBytecodeAttribute::GetPCAt(inferred_type_attr, 0) ==
+         InferredTypeBytecodeAttribute::kFieldTypePC)) {
+      const InferredTypeMetadata type =
+          InferredTypeBytecodeAttribute::GetInferredTypeAt(
+              Z, inferred_type_attr, 0);
+      if (!type.IsTrivial()) {
+        field.set_guarded_cid(type.cid);
+        field.set_is_nullable(type.IsNullable());
+        field.set_guarded_list_length(Field::kNoFixedLength);
+      }
+    }
+  }
+}
+
 void BytecodeReaderHelper::ReadMembers(const Class& cls, bool discard_fields) {
   ASSERT(Thread::Current()->IsMutatorThread());
   ASSERT(cls.is_type_finalized());
@@ -1905,6 +1940,7 @@
   const int kHasPragmaFlag = 1 << 11;
   const int kHasCustomScriptFlag = 1 << 12;
   const int kHasInitializerCodeFlag = 1 << 13;
+  const int kHasAttributesFlag = 1 << 14;
 
   const int num_fields = reader_.ReadListLength();
   if ((num_fields == 0) && !cls.is_enum_class()) {
@@ -2051,6 +2087,10 @@
       }
     }
 
+    if ((flags & kHasAttributesFlag) != 0) {
+      ReadAttributes(field);
+    }
+
     fields.SetAt(i, field);
   }
 
@@ -2120,6 +2160,7 @@
   const int kHasAnnotationsFlag = 1 << 20;
   const int kHasPragmaFlag = 1 << 21;
   const int kHasCustomScriptFlag = 1 << 22;
+  const int kHasAttributesFlag = 1 << 23;
 
   const intptr_t num_functions = reader_.ReadListLength();
   ASSERT(function_index_ + num_functions == functions_->Length());
@@ -2296,6 +2337,11 @@
       }
     }
 
+    if ((flags & kHasAttributesFlag) != 0) {
+      ASSERT(!is_expression_evaluation);
+      ReadAttributes(function);
+    }
+
     if (is_expression_evaluation) {
       H.SetExpressionEvaluationFunction(function);
       // Read bytecode of expression evaluation function eagerly,
@@ -2906,6 +2952,12 @@
       (flags & Code::kHasForwardingStubTargetFlag) != 0;
   const bool has_default_function_type_args =
       (flags & Code::kHasDefaultFunctionTypeArgsFlag) != 0;
+  const auto proc_attrs = kernel::ProcedureAttributesOf(target, Z);
+  // TODO(alexmarkov): fix building of flow graph for implicit closures so
+  // it would include missing checks and remove 'proc_attrs.has_tearoff_uses'
+  // from this condition.
+  const bool body_has_generic_covariant_impl_type_checks =
+      proc_attrs.has_non_this_uses || proc_attrs.has_tearoff_uses;
 
   if (has_parameters_flags) {
     const intptr_t num_params = reader_.ReadUInt();
@@ -2925,7 +2977,8 @@
       }
 
       const bool checked_in_method_body =
-          is_covariant || is_generic_covariant_impl;
+          is_covariant || (is_generic_covariant_impl &&
+                           body_has_generic_covariant_impl_type_checks);
 
       if (checked_in_method_body) {
         variable->set_type_check_mode(LocalVariable::kSkipTypeCheck);
@@ -3442,6 +3495,45 @@
   bytecode_reader.ReadMembers(cls, discard_fields);
 }
 
+RawObject* BytecodeReader::GetBytecodeAttribute(const Object& key,
+                                                const String& name) {
+  Thread* thread = Thread::Current();
+  Zone* zone = thread->zone();
+  const auto* object_store = thread->isolate()->object_store();
+  if (object_store->bytecode_attributes() == Object::null()) {
+    return Object::null();
+  }
+  BytecodeAttributesMap map(object_store->bytecode_attributes());
+  const auto& attrs = Array::CheckedHandle(zone, map.GetOrNull(key));
+  ASSERT(map.Release().raw() == object_store->bytecode_attributes());
+  if (attrs.IsNull()) {
+    return Object::null();
+  }
+  auto& obj = Object::Handle(zone);
+  for (intptr_t i = 0, n = attrs.Length(); i + 1 < n; i += 2) {
+    obj = attrs.At(i);
+    if (obj.raw() == name.raw()) {
+      return attrs.At(i + 1);
+    }
+  }
+  return Object::null();
+}
+
+InferredTypeMetadata InferredTypeBytecodeAttribute::GetInferredTypeAt(
+    Zone* zone,
+    const Array& attr,
+    intptr_t index) {
+  ASSERT(index + kNumElements <= attr.Length());
+  const auto& type = AbstractType::CheckedHandle(zone, attr.At(index + 1));
+  const intptr_t flags = Smi::Value(Smi::RawCast(attr.At(index + 2)));
+  if (!type.IsNull()) {
+    intptr_t cid = Type::Cast(type).type_class_id();
+    return InferredTypeMetadata(cid, flags);
+  } else {
+    return InferredTypeMetadata(kDynamicCid, flags);
+  }
+}
+
 #if !defined(PRODUCT)
 RawLocalVarDescriptors* BytecodeReader::ComputeLocalVarDescriptors(
     Zone* zone,
diff --git a/runtime/vm/compiler/frontend/bytecode_reader.h b/runtime/vm/compiler/frontend/bytecode_reader.h
index 39951e5..418d021 100644
--- a/runtime/vm/compiler/frontend/bytecode_reader.h
+++ b/runtime/vm/compiler/frontend/bytecode_reader.h
@@ -215,6 +215,7 @@
   RawString* ReadString(bool is_canonical = true);
   RawScript* ReadSourceFile(const String& uri, intptr_t offset);
   RawTypeArguments* ReadTypeArguments();
+  void ReadAttributes(const Object& key);
   RawPatchClass* GetPatchClass(const Class& cls, const Script& script);
   void ParseForwarderFunction(ParsedFunction* parsed_function,
                               const Function& function,
@@ -357,6 +358,9 @@
   // Read members of the given class.
   static void FinishClassLoading(const Class& cls);
 
+  // Value of attribute [name] of Function/Field [key].
+  static RawObject* GetBytecodeAttribute(const Object& key, const String& name);
+
 #if !defined(PRODUCT)
   // Compute local variable descriptors for [function] with [bytecode].
   static RawLocalVarDescriptors* ComputeLocalVarDescriptors(
@@ -366,6 +370,26 @@
 #endif
 };
 
+class InferredTypeBytecodeAttribute : public AllStatic {
+ public:
+  // Number of array elements per entry in InferredType bytecode
+  // attribute (PC, type, flags).
+  static constexpr intptr_t kNumElements = 3;
+
+  // Field type is the first entry with PC = -1.
+  static constexpr intptr_t kFieldTypePC = -1;
+
+  // Returns PC at given index.
+  static intptr_t GetPCAt(const Array& attr, intptr_t index) {
+    return Smi::Value(Smi::RawCast(attr.At(index)));
+  }
+
+  // Returns InferredType metadata at given index.
+  static InferredTypeMetadata GetInferredTypeAt(Zone* zone,
+                                                const Array& attr,
+                                                intptr_t index);
+};
+
 class BytecodeSourcePositionsIterator : ValueObject {
  public:
   // These constants should match corresponding constants in class
@@ -531,6 +555,22 @@
   TokenPosition cur_end_token_pos_ = TokenPosition::kNoSource;
 };
 
+class BytecodeAttributesMapTraits {
+ public:
+  static const char* Name() { return "BytecodeAttributesMapTraits"; }
+  static bool ReportStats() { return false; }
+
+  static bool IsMatch(const Object& a, const Object& b) {
+    return a.raw() == b.raw();
+  }
+
+  static uword Hash(const Object& key) {
+    return String::HashRawSymbol(key.IsFunction() ? Function::Cast(key).name()
+                                                  : Field::Cast(key).name());
+  }
+};
+typedef UnorderedHashMap<BytecodeAttributesMapTraits> BytecodeAttributesMap;
+
 bool IsStaticFieldGetterGeneratedAsInitializer(const Function& function,
                                                Zone* zone);
 
diff --git a/runtime/vm/compiler/frontend/bytecode_scope_builder.cc b/runtime/vm/compiler/frontend/bytecode_scope_builder.cc
index 8da6b6e..fbc39dd 100644
--- a/runtime/vm/compiler/frontend/bytecode_scope_builder.cc
+++ b/runtime/vm/compiler/frontend/bytecode_scope_builder.cc
@@ -97,9 +97,14 @@
           const Field& field = Field::Handle(Z, function.accessor_field());
           if (field.is_covariant()) {
             setter_value->set_is_explicit_covariant_parameter();
-          } else if (!field.is_generic_covariant_impl()) {
-            setter_value->set_type_check_mode(
-                LocalVariable::kTypeCheckedByCaller);
+          } else {
+            const bool needs_type_check =
+                field.is_generic_covariant_impl() &&
+                kernel::ProcedureAttributesOf(field, Z).has_non_this_uses;
+            if (!needs_type_check) {
+              setter_value->set_type_check_mode(
+                  LocalVariable::kTypeCheckedByCaller);
+            }
           }
         }
       }
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index e5b6bf2..95c92b2 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -1728,6 +1728,18 @@
   return InferredTypeMetadata(cid, flags);
 }
 
+void ProcedureAttributesMetadata::InitializeFromFlags(uint8_t flags) {
+  const int kDynamicUsesBit = 1 << 0;
+  const int kNonThisUsesBit = 1 << 1;
+  const int kTearOffUsesBit = 1 << 2;
+  const int kThisUsesBit = 1 << 3;
+
+  has_dynamic_invocations = (flags & kDynamicUsesBit) != 0;
+  has_this_uses = (flags & kThisUsesBit) != 0;
+  has_non_this_uses = (flags & kNonThisUsesBit) != 0;
+  has_tearoff_uses = (flags & kTearOffUsesBit) != 0;
+}
+
 ProcedureAttributesMetadataHelper::ProcedureAttributesMetadataHelper(
     KernelReaderHelper* helper)
     : MetadataHelper(helper, tag(), /* precompiler_only = */ true) {}
@@ -1743,16 +1755,8 @@
   AlternativeReadingScopeWithNewData alt(&helper_->reader_,
                                          &H.metadata_payloads(), md_offset);
 
-  const int kDynamicUsesBit = 1 << 0;
-  const int kNonThisUsesBit = 1 << 1;
-  const int kTearOffUsesBit = 1 << 2;
-  const int kThisUsesBit = 1 << 3;
-
   const uint8_t flags = helper_->ReadByte();
-  metadata->has_dynamic_invocations = (flags & kDynamicUsesBit) != 0;
-  metadata->has_this_uses = (flags & kThisUsesBit) != 0;
-  metadata->has_non_this_uses = (flags & kNonThisUsesBit) != 0;
-  metadata->has_tearoff_uses = (flags & kTearOffUsesBit) != 0;
+  metadata->InitializeFromFlags(flags);
   return true;
 }
 
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h
index b8152f4..466bc18 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.h
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h
@@ -939,6 +939,8 @@
   bool has_this_uses = true;
   bool has_non_this_uses = true;
   bool has_tearoff_uses = true;
+
+  void InitializeFromFlags(uint8_t flags);
 };
 
 // Helper class which provides access to direct call metadata.
diff --git a/runtime/vm/constants_kbc.h b/runtime/vm/constants_kbc.h
index a89756e..a4b5d21 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 = 21;
+  static const intptr_t kMaxSupportedBytecodeFormatVersion = 22;
 
   enum Opcode {
 #define DECLARE_BYTECODE(name, encoding, kind, op1, op2, op3) k##name,
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 2271645..3f5212c 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -2780,6 +2780,11 @@
     return true;
   }
   ASSERT(exc_pause_info_ == kPauseOnUnhandledExceptions);
+  // Exceptions coming from invalid token positions should be skipped
+  ActivationFrame* top_frame = stack_trace->FrameAt(0);
+  if (!top_frame->TokenPos().IsReal() && top_frame->TryIndex() != -1) {
+    return false;
+  }
   ActivationFrame* handler_frame = stack_trace->GetHandlerFrame(exception);
   if (handler_frame == NULL) {
     // Did not find an exception handler that catches this exception.
diff --git a/runtime/vm/heap/compactor.cc b/runtime/vm/heap/compactor.cc
index 6a0bfbf..c327ce3 100644
--- a/runtime/vm/heap/compactor.cc
+++ b/runtime/vm/heap/compactor.cc
@@ -35,7 +35,10 @@
 // the block's new start address.
 class ForwardingBlock {
  public:
-  ForwardingBlock() : new_address_(0), live_bitvector_(0) {}
+  void Clear() {
+    new_address_ = 0;
+    live_bitvector_ = 0;
+  }
 
   uword Lookup(uword old_addr) const {
     uword block_offset = old_addr & ~kBlockMask;
@@ -87,7 +90,11 @@
 
 class ForwardingPage {
  public:
-  ForwardingPage() : blocks_() {}
+  void Clear() {
+    for (intptr_t i = 0; i < kBlocksPerPage; i++) {
+      blocks_[i].Clear();
+    }
+  }
 
   uword Lookup(uword old_addr) { return BlockFor(old_addr)->Lookup(old_addr); }
 
@@ -102,19 +109,16 @@
  private:
   ForwardingBlock blocks_[kBlocksPerPage];
 
-  DISALLOW_COPY_AND_ASSIGN(ForwardingPage);
+  DISALLOW_ALLOCATION();
+  DISALLOW_IMPLICIT_CONSTRUCTORS(ForwardingPage);
 };
 
-ForwardingPage* HeapPage::AllocateForwardingPage() {
+void HeapPage::AllocateForwardingPage() {
   ASSERT(forwarding_page_ == NULL);
-  forwarding_page_ = new ForwardingPage();
-  return forwarding_page_;
-}
-
-void HeapPage::FreeForwardingPage() {
-  ASSERT(forwarding_page_ != NULL);
-  delete forwarding_page_;
-  forwarding_page_ = NULL;
+  ASSERT((object_start() + sizeof(ForwardingPage)) < object_end());
+  ASSERT(Utils::IsAligned(sizeof(ForwardingPage), kObjectAlignment));
+  object_end_ -= sizeof(ForwardingPage);
+  forwarding_page_ = reinterpret_cast<ForwardingPage*>(object_end_);
 }
 
 class CompactorTask : public ThreadPool::Task {
@@ -301,7 +305,6 @@
         HeapPage* next = page->next();
         heap_->old_space()->IncreaseCapacityInWordsLocked(
             -(page->memory_->size() >> kWordSizeLog2));
-        page->FreeForwardingPage();
         page->Deallocate();
         page = next;
       }
@@ -318,11 +321,6 @@
     delete[] heads;
     delete[] tails;
   }
-
-  // Free forwarding information from the suriving pages.
-  for (HeapPage* page = pages; page != NULL; page = page->next()) {
-    page->FreeForwardingPage();
-  }
 }
 
 void CompactorTask::Run() {
@@ -430,7 +428,9 @@
   uword current = page->object_start();
   uword end = page->object_end();
 
-  auto forwarding_page = page->AllocateForwardingPage();
+  ForwardingPage* forwarding_page = page->forwarding_page();
+  ASSERT(forwarding_page != nullptr);
+  forwarding_page->Clear();
   while (current < end) {
     current = PlanBlock(current, forwarding_page);
   }
@@ -440,7 +440,8 @@
   uword current = page->object_start();
   uword end = page->object_end();
 
-  auto forwarding_page = page->forwarding_page();
+  ForwardingPage* forwarding_page = page->forwarding_page();
+  ASSERT(forwarding_page != nullptr);
   while (current < end) {
     current = SlideBlock(current, forwarding_page);
   }
@@ -603,6 +604,7 @@
 
   RawObject* new_target =
       RawObject::FromAddr(forwarding_page->Lookup(old_addr));
+  ASSERT(!new_target->IsSmiOrNewObject());
   *ptr = new_target;
 }
 
diff --git a/runtime/vm/heap/pages.cc b/runtime/vm/heap/pages.cc
index 88222d0..17446eb 100644
--- a/runtime/vm/heap/pages.cc
+++ b/runtime/vm/heap/pages.cc
@@ -6,6 +6,7 @@
 
 #include "platform/address_sanitizer.h"
 #include "platform/assert.h"
+#include "vm/dart.h"
 #include "vm/heap/become.h"
 #include "vm/heap/compactor.h"
 #include "vm/heap/marker.h"
@@ -72,8 +73,6 @@
 }
 
 void HeapPage::Deallocate() {
-  ASSERT(forwarding_page_ == NULL);
-
   if (card_table_ != NULL) {
     free(card_table_);
     card_table_ = NULL;
@@ -328,6 +327,10 @@
   }
 
   page->set_object_end(page->memory_->end());
+  if ((type != HeapPage::kExecutable) && (heap_ != nullptr) &&
+      (heap_->isolate() != Dart::vm_isolate())) {
+    page->AllocateForwardingPage();
+  }
   return page;
 }
 
diff --git a/runtime/vm/heap/pages.h b/runtime/vm/heap/pages.h
index 736fa30..3341eec 100644
--- a/runtime/vm/heap/pages.h
+++ b/runtime/vm/heap/pages.h
@@ -50,8 +50,7 @@
   }
 
   ForwardingPage* forwarding_page() const { return forwarding_page_; }
-  ForwardingPage* AllocateForwardingPage();
-  void FreeForwardingPage();
+  void AllocateForwardingPage();
 
   PageType type() const { return type_; }
 
diff --git a/runtime/vm/kernel.cc b/runtime/vm/kernel.cc
index 2b82f32..8e2dbec 100644
--- a/runtime/vm/kernel.cc
+++ b/runtime/vm/kernel.cc
@@ -800,11 +800,29 @@
   return attrs;
 }
 
+static ProcedureAttributesMetadata ProcedureAttributesFromBytecodeAttribute(
+    Zone* zone,
+    const Object& function_or_field) {
+  ProcedureAttributesMetadata attrs;
+  const auto& value = Object::Handle(
+      zone,
+      BytecodeReader::GetBytecodeAttribute(
+          function_or_field, Symbols::vm_procedure_attributes_metadata()));
+  if (!value.IsNull()) {
+    if (!value.IsSmi()) {
+      FATAL3("Unexpected value of %s bytecode attribute on %s: %s",
+             Symbols::vm_procedure_attributes_metadata().ToCString(),
+             function_or_field.ToCString(), value.ToCString());
+    }
+    attrs.InitializeFromFlags(Smi::Cast(value).Value());
+  }
+  return attrs;
+}
+
 ProcedureAttributesMetadata ProcedureAttributesOf(const Function& function,
                                                   Zone* zone) {
   if (function.is_declared_in_bytecode()) {
-    // TODO(alexmarkov): add AOT metadata to bytecode.
-    return ProcedureAttributesMetadata();
+    return ProcedureAttributesFromBytecodeAttribute(zone, function);
   }
   const Script& script = Script::Handle(zone, function.script());
   return ProcedureAttributesOf(
@@ -815,8 +833,7 @@
 ProcedureAttributesMetadata ProcedureAttributesOf(const Field& field,
                                                   Zone* zone) {
   if (field.is_declared_in_bytecode()) {
-    // TODO(alexmarkov): add AOT metadata to bytecode.
-    return ProcedureAttributesMetadata();
+    return ProcedureAttributesFromBytecodeAttribute(zone, field);
   }
   const Class& parent = Class::Handle(zone, field.Owner());
   const Script& script = Script::Handle(zone, parent.script());
diff --git a/runtime/vm/kernel_isolate.cc b/runtime/vm/kernel_isolate.cc
index abf3f55..82da67c 100644
--- a/runtime/vm/kernel_isolate.cc
+++ b/runtime/vm/kernel_isolate.cc
@@ -626,8 +626,8 @@
 
     Dart_CObject bytecode;
     bytecode.type = Dart_CObject_kBool;
-    // Interpreter is supported only on x64 and arm64.
-#if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_ARM64)
+    // Interpreter is not supported with DBC.
+#if !defined(TARGET_ARCH_DBC)
     bytecode.value.as_bool =
         FLAG_enable_interpreter || FLAG_use_bytecode_compiler;
 #else
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index 3a6e3e5..a0ce9f9 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -124,6 +124,7 @@
   RW(Function, async_star_move_next_helper)                                    \
   RW(Function, complete_on_async_return)                                       \
   RW(Class, async_star_stream_controller)                                      \
+  RW(Array, bytecode_attributes)                                               \
   RW(GrowableObjectArray, llvm_constant_pool)                                  \
   RW(GrowableObjectArray, llvm_function_pool)                                  \
   RW(Array, llvm_constant_hash_table)                                          \
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index c0f5f16..c95b589 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -462,9 +462,11 @@
   V(vm_prefer_inline, "vm:prefer-inline")                                      \
   V(vm_entry_point, "vm:entry-point")                                          \
   V(vm_exact_result_type, "vm:exact-result-type")                              \
+  V(vm_inferred_type_metadata, "vm.inferred-type.metadata")                    \
   V(vm_never_inline, "vm:never-inline")                                        \
   V(vm_non_nullable_result_type, "vm:non-nullable-result-type")                \
-  V(vm_trace_entrypoints, "vm:testing.unsafe.trace-entrypoints-fn")
+  V(vm_trace_entrypoints, "vm:testing.unsafe.trace-entrypoints-fn")            \
+  V(vm_procedure_attributes_metadata, "vm.procedure-attributes.metadata")
 
 // Contains a list of frequently used strings in a canonicalized form. This
 // list is kept in the vm_isolate in order to share the copy across isolates
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index 9a4a1c5..22d6e0a 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -804,13 +804,12 @@
   visibility = [ ":copy_dev_compiler_sdk" ]
   deps = [
     ":copy_dev_compiler_js",
-    "../utils/dartdevc:dartdevc_web",
     "../utils/dartdevc:stack_trace_mapper",
   ]
-  dart_out = get_label_info("../utils/dartdevc:dartdevc_web", "root_out_dir")
+  dart_out =
+      get_label_info("../utils/dartdevc:stack_trace_mapper", "root_out_dir")
   sources = [
     "$dart_out/dev_compiler/build/web/dart_stack_trace_mapper.js",
-    "$dart_out/dev_compiler/build/web/ddc_web_compiler.js",
   ]
   outputs = [
     "$root_out_dir/dart-sdk/lib/dev_compiler/web/{{source_file_part}}",
diff --git a/sdk/lib/_internal/js_runtime/lib/rti.dart b/sdk/lib/_internal/js_runtime/lib/rti.dart
index dba3d2a..da9f7cf 100644
--- a/sdk/lib/_internal/js_runtime/lib/rti.dart
+++ b/sdk/lib/_internal/js_runtime/lib/rti.dart
@@ -98,6 +98,11 @@
   dynamic _precomputed3;
   dynamic _precomputed4;
 
+  static Rti _getPrecomputed1(Rti rti) => _castToRti(rti._precomputed1);
+  static void _setPrecomputed1(Rti rti, Rti precomputed) {
+    rti._precomputed1 = precomputed;
+  }
+
   // The Type object corresponding to this Rti.
   Object _cachedRuntimeType;
   static _Type _getCachedRuntimeType(Rti rti) =>
@@ -1495,6 +1500,10 @@
     Rti._setKind(rti, Rti.kindInterface);
     Rti._setPrimary(rti, name);
     Rti._setRest(rti, typeArguments);
+    int length = _Utils.arrayLength(typeArguments);
+    if (length > 0) {
+      Rti._setPrecomputed1(rti, _castToRti(_Utils.arrayAt(typeArguments, 0)));
+    }
     Rti._setCanonicalRecipe(rti, key);
     return _finishRti(universe, rti);
   }
@@ -2077,6 +2086,7 @@
     if (kind != Rti.kindInterface) {
       throw AssertionError('Indexed base must be an interface type');
     }
+    if (index == 1) return Rti._getPrecomputed1(environment);
     var typeArguments = Rti._getInterfaceTypeArguments(environment);
     int len = _Utils.arrayLength(typeArguments);
     if (index <= len) {
diff --git a/sdk/lib/developer/timeline.dart b/sdk/lib/developer/timeline.dart
index 02f9c98..5658e1e 100644
--- a/sdk/lib/developer/timeline.dart
+++ b/sdk/lib/developer/timeline.dart
@@ -180,11 +180,23 @@
 /// [TimelineTask] in the other isolate.
 class TimelineTask {
   /// Create a task. The task ID will be set by the system.
-  TimelineTask() : _taskId = _getNextAsyncId() {}
+  ///
+  /// 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({TimelineTask parent})
+      : _parent = parent,
+        _taskId = _getNextAsyncId() {}
 
   /// Create a task with an explicit [taskId]. This is useful if you are
   /// passing a task from one isolate to another.
-  TimelineTask.withTaskId(int taskId) : _taskId = taskId {
+  ///
+  /// 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,
+        _taskId = taskId {
     ArgumentError.checkNotNull(taskId, 'taskId');
   }
 
@@ -195,7 +207,10 @@
     ArgumentError.checkNotNull(name, 'name');
     var block = new _AsyncBlock._(name, _taskId);
     _stack.add(block);
-    block._start(arguments);
+    block._start({
+      if (arguments != null) ...arguments,
+      if (_parent != null) 'parentId': _parent._taskId.toRadixString(16),
+    });
   }
 
   /// Emit an instant event for this task.
@@ -237,6 +252,7 @@
     return r;
   }
 
+  final TimelineTask _parent;
   final int _taskId;
   final List<_AsyncBlock> _stack = [];
 }
diff --git a/sdk/lib/libraries.json b/sdk/lib/libraries.json
index a6c8390..5d1e2a5 100644
--- a/sdk/lib/libraries.json
+++ b/sdk/lib/libraries.json
@@ -143,9 +143,6 @@
         "patches": "_internal/vm/lib/convert_patch.dart",
         "uri": "convert/convert.dart"
       },
-      "profiler": {
-        "uri": "profiler/profiler.dart"
-      },
       "math": {
         "patches": "_internal/vm/lib/math_patch.dart",
         "uri": "math/math.dart"
diff --git a/sdk/lib/libraries.yaml b/sdk/lib/libraries.yaml
index a4358e5..bffd897 100644
--- a/sdk/lib/libraries.yaml
+++ b/sdk/lib/libraries.yaml
@@ -140,9 +140,6 @@
     nativewrappers:
       uri: "html/dartium/nativewrappers.dart"
 
-    profiler:
-      uri: "profiler/profiler.dart"
-
     cli:
       uri: "cli/cli.dart"
       patches:
diff --git a/sdk_nnbd/BUILD.gn b/sdk_nnbd/BUILD.gn
index 6d96000..22d6e0a 100644
--- a/sdk_nnbd/BUILD.gn
+++ b/sdk_nnbd/BUILD.gn
@@ -9,8 +9,8 @@
 #
 # Warning:
 # If you need to copy something into dart-sdk/lib/foo in addition to the stuff
-# copied there by :copy_libraries_nnbd, then you must depend on ":copy_libraries_nnbd",
-# or ":copy_libraries_nnbd" may delete/overwrite your addition, and the build will
+# copied there by :copy_libraries, then you must depend on ":copy_libraries",
+# or ":copy_libraries" may delete/overwrite your addition, and the build will
 # fail.
 
 import("../build/dart/copy_tree.gni")
@@ -18,15 +18,12 @@
 
 declare_args() {
   # Build a SDK with less stuff. It excludes dart2js, ddc, and web libraries.
-  dart_platform_sdk_nnbd = true
+  dart_platform_sdk = true
 
   # Path to stripped dart binaries relative to build output directory.
-  # TODO(rnystrom): These should use different filenames once the runtime's
-  # BUILD.gn file has additional rules to generate the NNBD versions of these
-  # executables.
-  dart_stripped_binary_nnbd = "dart"
-  dartaotruntime_stripped_binary_nnbd = "dartaotruntime"
-  gen_snapshot_stripped_binary_nnbd = "gen_snapshot"
+  dart_stripped_binary = "dart"
+  dartaotruntime_stripped_binary = "dartaotruntime"
+  gen_snapshot_stripped_binary = "gen_snapshot"
 }
 
 # The directory layout of the SDK is as follows:
@@ -255,10 +252,10 @@
 # bin/resources/dartdoc/templates
 copy_tree_specs += [
   {
-    target = "copy_dartdoc_templates_nnbd"
-    visibility = [ ":copy_dartdoc_files_nnbd" ]
+    target = "copy_dartdoc_templates"
+    visibility = [ ":copy_dartdoc_files" ]
     source = "../third_party/pkg/dartdoc/lib/templates"
-    dest = "$root_out_dir/dart-sdk-nnbd/bin/resources/dartdoc/templates"
+    dest = "$root_out_dir/dart-sdk/bin/resources/dartdoc/templates"
     ignore_patterns = "{}"
   },
 ]
@@ -267,10 +264,10 @@
 # bin/resources/dartdoc/resources
 copy_tree_specs += [
   {
-    target = "copy_dartdoc_resources_nnbd"
-    visibility = [ ":copy_dartdoc_files_nnbd" ]
+    target = "copy_dartdoc_resources"
+    visibility = [ ":copy_dartdoc_files" ]
     source = "../third_party/pkg/dartdoc/lib/resources"
-    dest = "$root_out_dir/dart-sdk-nnbd/bin/resources/dartdoc/resources"
+    dest = "$root_out_dir/dart-sdk/bin/resources/dartdoc/resources"
     ignore_patterns = "{}"
   },
 ]
@@ -279,13 +276,13 @@
 foreach(library, _full_sdk_libraries) {
   copy_tree_specs += [
     {
-      target = "copy_${library}_library_nnbd"
+      target = "copy_${library}_library"
       visibility = [
-        ":copy_platform_sdk_libraries_nnbd",
-        ":copy_full_sdk_libraries_nnbd",
+        ":copy_platform_sdk_libraries",
+        ":copy_full_sdk_libraries",
       ]
       source = "lib/$library"
-      dest = "$root_out_dir/dart-sdk-nnbd/lib/$library"
+      dest = "$root_out_dir/dart-sdk/lib/$library"
       ignore_patterns = "*.svn,doc,*.py,*.gypi,*.sh,.gitignore"
     },
   ]
@@ -294,13 +291,13 @@
 if (is_win) {
   copy_tree_specs += [
     {
-      target = "copy_7zip_nnbd"
-      visibility = [ ":create_common_sdk_nnbd" ]
+      target = "copy_7zip"
+      visibility = [ ":create_common_sdk" ]
       deps = [
-        ":copy_libraries_nnbd",
+        ":copy_libraries",
       ]
       source = "../third_party/7zip"
-      dest = "$root_out_dir/dart-sdk-nnbd/lib/_internal/pub/asset/7zip"
+      dest = "$root_out_dir/dart-sdk/lib/_internal/pub/asset/7zip"
       ignore_patterns = ".svn"
     },
   ]
@@ -309,23 +306,23 @@
 if (target_cpu == "x64") {
   copy_tree_specs += [
     {
-      target = "copy_language_model_nnbd"
-      visibility = [ ":create_common_sdk_nnbd" ]
+      target = "copy_language_model"
+      visibility = [ ":create_common_sdk" ]
       deps = [
-        ":copy_libraries_nnbd",
+        ":copy_libraries",
       ]
       source = "../pkg/analysis_server/language_model"
-      dest = "$root_out_dir/dart-sdk-nnbd/model"
+      dest = "$root_out_dir/dart-sdk/model"
       ignore_patterns = "{}"
     },
     {
-      target = "copy_libtensorflowlite_c_nnbd"
-      visibility = [ ":create_common_sdk_nnbd" ]
+      target = "copy_libtensorflowlite_c"
+      visibility = [ ":create_common_sdk" ]
       deps = [
-        ":copy_libraries_nnbd",
+        ":copy_libraries",
       ]
       source = "../third_party/pkg/tflite_native/lib/src/blobs"
-      dest = "$root_out_dir/dart-sdk-nnbd/bin/snapshots"
+      dest = "$root_out_dir/dart-sdk/bin/snapshots"
       ignore_patterns = "{}"
     },
   ]
@@ -333,7 +330,7 @@
 
 # This generates targets for everything in copy_tree_specs. The targets have the
 # same name as the "target" fields in the scopes of copy_tree_specs.
-copy_trees("copy_trees_nnbd") {
+copy_trees("copy_trees") {
   sources = copy_tree_specs
 }
 
@@ -351,19 +348,18 @@
   # make a link to the symlink rather than the symlink's target, and the
   # relative symlink interpreted from a different containing directory
   # will not find the actual binary.
-  action("copy_dart_nnbd") {
-    visibility = [ ":create_common_sdk_nnbd" ]
-    # TODO(rnystrom): This probably needs to be forked for NNBD.
+  action("copy_dart") {
+    visibility = [ ":create_common_sdk" ]
     dart_label = "../runtime/bin:dart"
     deps = [
       dart_label,
     ]
     dart_out = get_label_info(dart_label, "root_out_dir")
     sources = [
-      "$dart_out/$dart_stripped_binary_nnbd",
+      "$dart_out/$dart_stripped_binary",
     ]
     outputs = [
-      "$root_out_dir/dart-sdk-nnbd/bin/$dart_stripped_binary_nnbd",
+      "$root_out_dir/dart-sdk/bin/$dart_stripped_binary",
     ]
     script = "/bin/ln"
     args = [
@@ -373,33 +369,31 @@
     ]
   }
 } else {
-  copy("copy_dart_nnbd") {
-    visibility = [ ":create_common_sdk_nnbd" ]
+  copy("copy_dart") {
+    visibility = [ ":create_common_sdk" ]
     deps = [
-      # TODO(rnystrom): This probably needs to be forked for NNBD.
       "../runtime/bin:dart",
     ]
     dart_out = get_label_info("../runtime/bin:dart", "root_out_dir")
     if (is_win) {
       sources = [
-        # TODO(rnystrom): This probably needs to be forked for NNBD.
         "$dart_out/dart.exe",
       ]
     } else {
       sources = [
-        "$dart_out/$dart_stripped_binary_nnbd",
+        "$dart_out/$dart_stripped_binary",
       ]
     }
     if (is_win) {
       sources += [ "$dart_out/dart.lib" ]
     }
     outputs = [
-      "$root_out_dir/dart-sdk-nnbd/bin/{{source_file_part}}",
+      "$root_out_dir/dart-sdk/bin/{{source_file_part}}",
     ]
   }
 }
 
-copy("copy_dartaotruntime_nnbd") {
+copy("copy_dartaotruntime") {
   deps = [
     "../runtime/bin:dartaotruntime",
   ]
@@ -411,40 +405,38 @@
     ]
   } else {
     sources = [
-      "$dartaotruntime_out/$dartaotruntime_stripped_binary_nnbd",
+      "$dartaotruntime_out/$dartaotruntime_stripped_binary",
     ]
   }
   if (is_win) {
     sources += [ "$dartaotruntime_out/dartaotruntime.lib" ]
   }
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/bin/{{source_file_part}}",
+    "$root_out_dir/dart-sdk/bin/{{source_file_part}}",
   ]
 }
 
-copy("copy_gen_snapshot_nnbd") {
+copy("copy_gen_snapshot") {
   deps = [
-    # TODO(rnystrom): This probably needs to be forked for NNBD.
     "../runtime/bin:gen_snapshot",
   ]
   gen_snapshot_out =
       get_label_info("../runtime/bin:gen_snapshot", "root_out_dir")
   if (is_win) {
     sources = [
-      # TODO(rnystrom): This probably needs to be forked for NNBD.
       "$gen_snapshot_out/gen_snapshot.exe",
     ]
   } else {
     sources = [
-      "$gen_snapshot_out/$gen_snapshot_stripped_binary_nnbd",
+      "$gen_snapshot_out/$gen_snapshot_stripped_binary",
     ]
   }
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/bin/utils/{{source_file_part}}",
+    "$root_out_dir/dart-sdk/bin/utils/{{source_file_part}}",
   ]
 }
 
-copy("copy_dart2aot_nnbd") {
+copy("copy_dart2aot") {
   ext = ""
   if (is_win) {
     ext = ".bat"
@@ -453,14 +445,14 @@
     "bin/dart2aot$ext",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/bin/{{source_file_part}}",
+    "$root_out_dir/dart-sdk/bin/{{source_file_part}}",
   ]
 }
 
-copy("copy_dart2native_nnbd") {
+copy("copy_dart2native") {
   deps = [
-    ":copy_gen_kernel_snapshot_nnbd",
-    ":copy_gen_snapshot_nnbd",
+    ":copy_gen_kernel_snapshot",
+    ":copy_gen_snapshot",
   ]
   ext = ""
   if (is_win) {
@@ -470,27 +462,26 @@
     "bin/dart2native$ext",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/bin/{{source_file_part}}",
+    "$root_out_dir/dart-sdk/bin/{{source_file_part}}",
   ]
 }
 
-copy("copy_gen_kernel_snapshot_nnbd") {
+copy("copy_gen_kernel_snapshot") {
   deps = [
     "../utils/gen_kernel",
   ]
   sources = [
-    # TODO(rnystrom): This probably needs to be forked for NNBD.
     "$root_gen_dir/gen_kernel.dart.snapshot",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/bin/snapshots/{{source_file_part}}",
+    "$root_out_dir/dart-sdk/bin/snapshots/{{source_file_part}}",
   ]
 }
 
 # A template for copying the things in _platform_sdk_scripts and
 # _full_sdk_scripts into bin/
-template("copy_sdk_script_nnbd") {
-  assert(defined(invoker.name), "copy_sdk_script_nnbd must define 'name'")
+template("copy_sdk_script") {
+  assert(defined(invoker.name), "copy_sdk_script must define 'name'")
   name = invoker.name
   ext = ""
   if (is_win) {
@@ -498,29 +489,29 @@
   }
   copy(target_name) {
     visibility = [
-      ":copy_platform_sdk_scripts_nnbd",
-      ":copy_full_sdk_scripts_nnbd",
+      ":copy_platform_sdk_scripts",
+      ":copy_full_sdk_scripts",
     ]
     sources = [
       "bin/${name}_sdk$ext",
     ]
     outputs = [
-      "$root_out_dir/dart-sdk-nnbd/bin/$name$ext",
+      "$root_out_dir/dart-sdk/bin/$name$ext",
     ]
   }
 }
 
 foreach(sdk_script, _full_sdk_scripts) {
-  copy_sdk_script_nnbd("copy_${sdk_script}_script_nnbd") {
+  copy_sdk_script("copy_${sdk_script}_script") {
     name = sdk_script
   }
 }
 
 foreach(script, _scripts) {
-  copy("copy_${script}_script_nnbd") {
+  copy("copy_${script}_script") {
     visibility = [
-      ":copy_platform_sdk_scripts_nnbd",
-      ":copy_full_sdk_scripts_nnbd",
+      ":copy_platform_sdk_scripts",
+      ":copy_full_sdk_scripts",
     ]
     ext = ""
     if (is_win) {
@@ -530,164 +521,159 @@
       "bin/$script$ext",
     ]
     outputs = [
-      "$root_out_dir/dart-sdk-nnbd/bin/{{source_file_part}}",
+      "$root_out_dir/dart-sdk/bin/{{source_file_part}}",
     ]
   }
 }
 
 # This is the main target for copying scripts in _platform_sdk_scripts to bin/
-group("copy_platform_sdk_scripts_nnbd") {
-  visibility = [ ":create_platform_sdk_nnbd" ]
+group("copy_platform_sdk_scripts") {
+  visibility = [ ":create_platform_sdk" ]
   public_deps = []
   foreach(sdk_script, _platform_sdk_scripts) {
-    public_deps += [ ":copy_${sdk_script}_script_nnbd" ]
+    public_deps += [ ":copy_${sdk_script}_script" ]
   }
   foreach(script, _scripts) {
-    public_deps += [ ":copy_${script}_script_nnbd" ]
+    public_deps += [ ":copy_${script}_script" ]
   }
 }
 
 # This is the main target for copying scripts in _full_sdk_scripts to bin/
-group("copy_full_sdk_scripts_nnbd") {
-  visibility = [ ":create_full_sdk_nnbd" ]
+group("copy_full_sdk_scripts") {
+  visibility = [ ":create_full_sdk" ]
   public_deps = []
   foreach(sdk_script, _full_sdk_scripts) {
-    public_deps += [ ":copy_${sdk_script}_script_nnbd" ]
+    public_deps += [ ":copy_${sdk_script}_script" ]
   }
   foreach(script, _scripts) {
-    public_deps += [ ":copy_${script}_script_nnbd" ]
+    public_deps += [ ":copy_${script}_script" ]
   }
 }
 
 # This loop generates "copy" targets that put snapshots into bin/snapshots
 foreach(snapshot, _full_sdk_snapshots) {
-  copy("copy_${snapshot[0]}_snapshot_nnbd") {
+  copy("copy_${snapshot[0]}_snapshot") {
     visibility = [
-      ":copy_platform_sdk_snapshots_nnbd",
-      ":copy_full_sdk_snapshots_nnbd",
+      ":copy_platform_sdk_snapshots",
+      ":copy_full_sdk_snapshots",
     ]
     deps = [
       snapshot[1],
     ]
     sources = [
-      # TODO(rnystrom): This probably needs to be forked for NNBD.
       "$root_gen_dir/${snapshot[0]}.dart.snapshot",
     ]
     outputs = [
-      "$root_out_dir/dart-sdk-nnbd/bin/snapshots/{{source_file_part}}",
+      "$root_out_dir/dart-sdk/bin/snapshots/{{source_file_part}}",
     ]
   }
 }
 
 # This is the main rule for copying snapshots from _platform_sdk_snapshots to
 # bin/snapshots
-group("copy_platform_sdk_snapshots_nnbd") {
-  visibility = [ ":create_platform_sdk_nnbd" ]
+group("copy_platform_sdk_snapshots") {
+  visibility = [ ":create_platform_sdk" ]
   public_deps = []
   foreach(snapshot, _platform_sdk_snapshots) {
-    public_deps += [ ":copy_${snapshot[0]}_snapshot_nnbd" ]
+    public_deps += [ ":copy_${snapshot[0]}_snapshot" ]
   }
 }
 
 # This is the main rule for copying snapshots from _full_sdk_snapshots to
 # bin/snapshots
-group("copy_full_sdk_snapshots_nnbd") {
-  visibility = [ ":create_full_sdk_nnbd" ]
+group("copy_full_sdk_snapshots") {
+  visibility = [ ":create_full_sdk" ]
   public_deps = []
   foreach(snapshot, _full_sdk_snapshots) {
-    public_deps += [ ":copy_${snapshot[0]}_snapshot_nnbd" ]
+    public_deps += [ ":copy_${snapshot[0]}_snapshot" ]
   }
 }
 
 # This rule writes the .packages file for dartdoc resources.
-write_file("$root_out_dir/dart-sdk-nnbd/bin/resources/dartdoc/.packages",
+write_file("$root_out_dir/dart-sdk/bin/resources/dartdoc/.packages",
            "dartdoc:.")
 
 # This is the main rule for copying the files that dartdoc needs.
-group("copy_dartdoc_files_nnbd") {
-  visibility = [ ":create_common_sdk_nnbd" ]
+group("copy_dartdoc_files") {
+  visibility = [ ":create_common_sdk" ]
   public_deps = [
-    ":copy_dartdoc_resources_nnbd",
-    ":copy_dartdoc_templates_nnbd",
+    ":copy_dartdoc_resources",
+    ":copy_dartdoc_templates",
   ]
 }
 
 # This rule copies analyzer summaries to lib/_internal
-copy("copy_analysis_summaries_nnbd") {
-  visibility = [ ":create_common_sdk_nnbd" ]
+copy("copy_analysis_summaries") {
+  visibility = [ ":create_common_sdk" ]
   deps = [
-    ":copy_libraries_nnbd",
+    ":copy_libraries",
     "../utils/dartanalyzer:generate_summary_strong",
   ]
   sources = [
     "$root_gen_dir/strong.sum",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/lib/_internal/{{source_file_part}}",
+    "$root_out_dir/dart-sdk/lib/_internal/{{source_file_part}}",
   ]
 }
 
 # This rule copies dill files to lib/_internal.
-copy("copy_vm_dill_files_nnbd") {
-  visibility = [ ":create_common_sdk_nnbd" ]
+copy("copy_vm_dill_files") {
+  visibility = [ ":create_common_sdk" ]
   deps = [
-    ":copy_libraries_nnbd",
+    ":copy_libraries",
     "../runtime/vm:kernel_platform_files",
   ]
   sources = [
-    # TODO(rnystrom): This probably needs to be forked for NNBD.
     "$root_out_dir/vm_platform_strong.dill",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/lib/_internal/{{source_file_part}}",
+    "$root_out_dir/dart-sdk/lib/_internal/{{source_file_part}}",
   ]
 }
 
-copy("copy_abi_dill_files_nnbd") {
-  visibility = [ ":create_sdk_with_abi_versions_nnbd" ]
+copy("copy_abi_dill_files") {
+  visibility = [ ":create_sdk_with_abi_versions" ]
   sources = [
-    # TODO(rnystrom): This probably needs to be forked for NNBD.
     "../tools/abiversions",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/lib/_internal/abiversions",
+    "$root_out_dir/dart-sdk/lib/_internal/abiversions",
   ]
 }
 
-copy("copy_dart2js_dill_files_nnbd") {
-  visibility = [ ":create_full_sdk_nnbd" ]
+copy("copy_dart2js_dill_files") {
+  visibility = [ ":create_full_sdk" ]
   deps = [
-    ":copy_libraries_nnbd",
+    ":copy_libraries",
     "../utils/compiler:compile_dart2js_platform",
     "../utils/compiler:compile_dart2js_server_platform",
   ]
   sources = [
-    # TODO(rnystrom): This probably needs to be forked for NNBD.
     "$root_out_dir/dart2js_platform.dill",
     "$root_out_dir/dart2js_server_platform.dill",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/lib/_internal/{{source_file_part}}",
+    "$root_out_dir/dart-sdk/lib/_internal/{{source_file_part}}",
   ]
 }
 
 # This rule copies ddc summaries to lib/_internal
-copy("copy_dev_compiler_summary_nnbd") {
-  visibility = [ ":copy_dev_compiler_sdk_nnbd" ]
+copy("copy_dev_compiler_summary") {
+  visibility = [ ":copy_dev_compiler_sdk" ]
   deps = [
-    ":copy_libraries_nnbd",
+    ":copy_libraries",
     "../utils/dartdevc:dartdevc_kernel_sdk_outline",
     "../utils/dartdevc:dartdevc_sdk",
   ]
   gen_dir = get_label_info("../utils/dartdevc:dartdevc_sdk", "target_gen_dir")
   sources = [
-    # TODO(rnystrom): This probably needs to be forked for NNBD.
     # TODO(vsm): Remove post CFE.
     "$gen_dir/ddc_sdk.sum",
     "$gen_dir/kernel/ddc_sdk.dill",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/lib/_internal/{{source_file_part}}",
+    "$root_out_dir/dart-sdk/lib/_internal/{{source_file_part}}",
   ]
 }
 
@@ -695,229 +681,222 @@
 # DDC to Kernel (DDK) migration.
 
 # This rule copies DDC's JS SDK and require.js to lib/dev_compiler/amd.
-copy("copy_dev_compiler_js_amd_nnbd") {
-  visibility = [ ":copy_dev_compiler_js_nnbd" ]
+copy("copy_dev_compiler_js_amd") {
+  visibility = [ ":copy_dev_compiler_js" ]
   deps = [
     "../utils/dartdevc:dartdevc_sdk",
   ]
   gen_dir = get_label_info("../utils/dartdevc:dartdevc_sdk", "target_gen_dir")
   sources = [
-    # TODO(rnystrom): This probably needs to be forked for NNBD.
     "$gen_dir/js/amd/dart_sdk.js",
     "$gen_dir/js/amd/dart_sdk.js.map",
     "../third_party/requirejs/require.js",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/lib/dev_compiler/amd/{{source_file_part}}",
+    "$root_out_dir/dart-sdk/lib/dev_compiler/amd/{{source_file_part}}",
   ]
 }
 
 # This rule copies DDC's JS SDK and run.js to lib/dev_compiler/common.
-copy("copy_dev_compiler_js_common_nnbd") {
-  visibility = [ ":copy_dev_compiler_js_nnbd" ]
+copy("copy_dev_compiler_js_common") {
+  visibility = [ ":copy_dev_compiler_js" ]
   deps = [
     "../utils/dartdevc:dartdevc_sdk",
   ]
   gen_dir = get_label_info("../utils/dartdevc:dartdevc_sdk", "target_gen_dir")
   sources = [
-    # TODO(rnystrom): This probably needs to be forked for NNBD.
     "$gen_dir/js/common/dart_sdk.js",
     "$gen_dir/js/common/dart_sdk.js.map",
     "../pkg/dev_compiler/lib/js/common/run.js",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/lib/dev_compiler/common/{{source_file_part}}",
+    "$root_out_dir/dart-sdk/lib/dev_compiler/common/{{source_file_part}}",
   ]
 }
 
 # This rule copies DDC's JS SDK to lib/dev_compiler/es6.
-copy("copy_dev_compiler_js_es6_nnbd") {
-  visibility = [ ":copy_dev_compiler_js_nnbd" ]
+copy("copy_dev_compiler_js_es6") {
+  visibility = [ ":copy_dev_compiler_js" ]
   deps = [
     "../utils/dartdevc:dartdevc_sdk",
   ]
   gen_dir = get_label_info("../utils/dartdevc:dartdevc_sdk", "target_gen_dir")
   sources = [
-    # TODO(rnystrom): This probably needs to be forked for NNBD.
     "$gen_dir/js/es6/dart_sdk.js",
     "$gen_dir/js/es6/dart_sdk.js.map",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/lib/dev_compiler/es6/{{source_file_part}}",
+    "$root_out_dir/dart-sdk/lib/dev_compiler/es6/{{source_file_part}}",
   ]
 }
 
 # This rule copies DDK's JS SDK and require.js to lib/dev_compiler/kernel/amd.
-copy("copy_dev_compiler_js_amd_kernel_nnbd") {
-  visibility = [ ":copy_dev_compiler_js_nnbd" ]
+copy("copy_dev_compiler_js_amd_kernel") {
+  visibility = [ ":copy_dev_compiler_js" ]
   deps = [
     "../utils/dartdevc:dartdevc_kernel_sdk",
   ]
   gen_dir =
       get_label_info("../utils/dartdevc:dartdevc_kernel_sdk", "target_gen_dir")
   sources = [
-    # TODO(rnystrom): This probably needs to be forked for NNBD.
     "$gen_dir/kernel/amd/dart_sdk.js",
     "$gen_dir/kernel/amd/dart_sdk.js.map",
     "../third_party/requirejs/require.js",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/lib/dev_compiler/kernel/amd/{{source_file_part}}",
+    "$root_out_dir/dart-sdk/lib/dev_compiler/kernel/amd/{{source_file_part}}",
   ]
 }
 
 # This rule copies DDK's JS SDK to lib/dev_compiler/kernel/common.
-copy("copy_dev_compiler_js_common_kernel_nnbd") {
-  visibility = [ ":copy_dev_compiler_js_nnbd" ]
+copy("copy_dev_compiler_js_common_kernel") {
+  visibility = [ ":copy_dev_compiler_js" ]
   deps = [
     "../utils/dartdevc:dartdevc_kernel_sdk",
   ]
   gen_dir =
       get_label_info("../utils/dartdevc:dartdevc_kernel_sdk", "target_gen_dir")
   sources = [
-    # TODO(rnystrom): This probably needs to be forked for NNBD.
     "$gen_dir/kernel/common/dart_sdk.js",
     "$gen_dir/kernel/common/dart_sdk.js.map",
     "../pkg/dev_compiler/lib/js/common/run.js",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/lib/dev_compiler/kernel/common/{{source_file_part}}",
+    "$root_out_dir/dart-sdk/lib/dev_compiler/kernel/common/{{source_file_part}}",
   ]
 }
 
 # This rule copies DDK's JS SDK to lib/dev_compiler/kernel/es6.
-copy("copy_dev_compiler_js_es6_kernel_nnbd") {
-  visibility = [ ":copy_dev_compiler_js_nnbd" ]
+copy("copy_dev_compiler_js_es6_kernel") {
+  visibility = [ ":copy_dev_compiler_js" ]
   deps = [
     "../utils/dartdevc:dartdevc_kernel_sdk",
   ]
   gen_dir =
       get_label_info("../utils/dartdevc:dartdevc_kernel_sdk", "target_gen_dir")
   sources = [
-    # TODO(rnystrom): This probably needs to be forked for NNBD.
     "$gen_dir/kernel/es6/dart_sdk.js",
     "$gen_dir/kernel/es6/dart_sdk.js.map",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/lib/dev_compiler/kernel/es6/{{source_file_part}}",
+    "$root_out_dir/dart-sdk/lib/dev_compiler/kernel/es6/{{source_file_part}}",
   ]
 }
 
 # Copies all of the JS artifacts needed by DDC.
-group("copy_dev_compiler_js_nnbd") {
+group("copy_dev_compiler_js") {
   visibility = [
-    ":copy_dev_compiler_sdk_nnbd",
-    ":copy_dev_compiler_tools_nnbd",
+    ":copy_dev_compiler_sdk",
+    ":copy_dev_compiler_tools",
   ]
   public_deps = [
-    ":copy_dev_compiler_js_amd_nnbd",
-    ":copy_dev_compiler_js_amd_kernel_nnbd",
-    ":copy_dev_compiler_js_common_nnbd",
-    ":copy_dev_compiler_js_common_kernel_nnbd",
-    ":copy_dev_compiler_js_es6_nnbd",
-    ":copy_dev_compiler_js_es6_kernel_nnbd",
+    ":copy_dev_compiler_js_amd",
+    ":copy_dev_compiler_js_amd_kernel",
+    ":copy_dev_compiler_js_common",
+    ":copy_dev_compiler_js_common_kernel",
+    ":copy_dev_compiler_js_es6",
+    ":copy_dev_compiler_js_es6_kernel",
   ]
 }
 
 # This rule copies tools to go along with ddc.
-copy("copy_dev_compiler_tools_nnbd") {
-  visibility = [ ":copy_dev_compiler_sdk_nnbd" ]
+copy("copy_dev_compiler_tools") {
+  visibility = [ ":copy_dev_compiler_sdk" ]
   deps = [
-    ":copy_dev_compiler_js_nnbd",
-    "../utils/dartdevc:dartdevc_web",
+    ":copy_dev_compiler_js",
     "../utils/dartdevc:stack_trace_mapper",
   ]
-  dart_out = get_label_info("../utils/dartdevc:dartdevc_web", "root_out_dir")
+  dart_out =
+      get_label_info("../utils/dartdevc:stack_trace_mapper", "root_out_dir")
   sources = [
     "$dart_out/dev_compiler/build/web/dart_stack_trace_mapper.js",
-    "$dart_out/dev_compiler/build/web/ddc_web_compiler.js",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/lib/dev_compiler/web/{{source_file_part}}",
+    "$root_out_dir/dart-sdk/lib/dev_compiler/web/{{source_file_part}}",
   ]
 }
 
 # This is the main rule for copying ddc's dependencies to lib/
-group("copy_dev_compiler_sdk_nnbd") {
-  visibility = [ ":create_full_sdk_nnbd" ]
+group("copy_dev_compiler_sdk") {
+  visibility = [ ":create_full_sdk" ]
   public_deps = [
-    ":copy_dev_compiler_js_nnbd",
-    ":copy_dev_compiler_summary_nnbd",
-    ":copy_dev_compiler_tools_nnbd",
+    ":copy_dev_compiler_js",
+    ":copy_dev_compiler_summary",
+    ":copy_dev_compiler_tools",
   ]
 }
 
 # This rule copies header files to include/
-copy("copy_headers_nnbd") {
-  visibility = [ ":create_common_sdk_nnbd" ]
+copy("copy_headers") {
+  visibility = [ ":create_common_sdk" ]
   sources = [
     "../runtime/include/dart_api.h",
     "../runtime/include/dart_native_api.h",
     "../runtime/include/dart_tools_api.h",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/include/{{source_file_part}}",
+    "$root_out_dir/dart-sdk/include/{{source_file_part}}",
   ]
 }
 
 # This rule copies libraries.json files to lib/
-copy("copy_libraries_specification_nnbd") {
-  visibility = [ ":create_common_sdk_nnbd" ]
+copy("copy_libraries_specification") {
+  visibility = [ ":create_common_sdk" ]
   sources = [
     "lib/libraries.json",
   ]
   deps = [
-    ":copy_libraries_nnbd",
+    ":copy_libraries",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/lib/{{source_file_part}}",
+    "$root_out_dir/dart-sdk/lib/{{source_file_part}}",
   ]
 }
 
 # This is the main rule to copy libraries in _platform_sdk_libraries to lib/
-group("copy_platform_sdk_libraries_nnbd") {
+group("copy_platform_sdk_libraries") {
   visibility = [
-    ":create_platform_sdk_nnbd",
-    ":copy_libraries_nnbd",
+    ":create_platform_sdk",
+    ":copy_libraries",
   ]
   public_deps = []
   foreach(library, _platform_sdk_libraries) {
-    public_deps += [ ":copy_${library}_library_nnbd" ]
+    public_deps += [ ":copy_${library}_library" ]
   }
 }
 
 # This is the main rule to copy libraries in _full_sdk_libraries to lib/
-group("copy_full_sdk_libraries_nnbd") {
+group("copy_full_sdk_libraries") {
   visibility = [
-    ":create_full_sdk_nnbd",
-    ":copy_libraries_nnbd",
+    ":create_full_sdk",
+    ":copy_libraries",
   ]
   public_deps = []
   foreach(library, _full_sdk_libraries) {
-    public_deps += [ ":copy_${library}_library_nnbd" ]
+    public_deps += [ ":copy_${library}_library" ]
   }
 }
 
-group("copy_libraries_nnbd") {
-  if (dart_platform_sdk_nnbd) {
+group("copy_libraries") {
+  if (dart_platform_sdk) {
     public_deps = [
-      ":copy_platform_sdk_libraries_nnbd",
+      ":copy_platform_sdk_libraries",
     ]
   } else {
     public_deps = [
-      ":copy_full_sdk_libraries_nnbd",
+      ":copy_full_sdk_libraries",
     ]
   }
 }
 
 # This rule writes the version file.
-action("write_version_file_nnbd") {
-  visibility = [ ":create_common_sdk_nnbd" ]
+action("write_version_file") {
+  visibility = [ ":create_common_sdk" ]
   inputs = [
     "../tools/VERSION",
     "../.git/logs/HEAD",
   ]
-  output = "$root_out_dir/dart-sdk-nnbd/version"
+  output = "$root_out_dir/dart-sdk/version"
   outputs = [
     output,
   ]
@@ -929,12 +908,12 @@
 }
 
 # This rule writes the revision file.
-action("write_revision_file_nnbd") {
-  visibility = [ ":create_common_sdk_nnbd" ]
+action("write_revision_file") {
+  visibility = [ ":create_common_sdk" ]
   inputs = [
     "../.git/logs/HEAD",
   ]
-  output = "$root_out_dir/dart-sdk-nnbd/revision"
+  output = "$root_out_dir/dart-sdk/revision"
   outputs = [
     output,
   ]
@@ -952,48 +931,48 @@
 # of the analyzer package do not support the new location of this file. We
 # should be able to remove the old file once we release a newer version of
 # analyzer and popular frameworks have migrated to use it.
-copy("copy_libraries_dart_nnbd") {
-  visibility = [ ":create_common_sdk_nnbd" ]
+copy("copy_libraries_dart") {
+  visibility = [ ":create_common_sdk" ]
   deps = [
-    ":copy_libraries_nnbd",
+    ":copy_libraries",
   ]
   sources = [
     "lib/_internal/sdk_library_metadata/lib/libraries.dart",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/lib/_internal/{{source_file_part}}",
+    "$root_out_dir/dart-sdk/lib/_internal/{{source_file_part}}",
   ]
 }
 
 # This rule copies the README file.
-copy("copy_readme_nnbd") {
-  visibility = [ ":create_common_sdk_nnbd" ]
+copy("copy_readme") {
+  visibility = [ ":create_common_sdk" ]
   sources = [
     "../README.dart-sdk",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/README",
+    "$root_out_dir/dart-sdk/README",
   ]
 }
 
 # This rule copies the LICENSE file.
-copy("copy_license_nnbd") {
-  visibility = [ ":create_common_sdk_nnbd" ]
+copy("copy_license") {
+  visibility = [ ":create_common_sdk" ]
   sources = [
     "../LICENSE",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/LICENSE",
+    "$root_out_dir/dart-sdk/LICENSE",
   ]
 }
 
 # This rule generates a custom dartdoc_options.yaml file.
-action("write_dartdoc_options_nnbd") {
-  visibility = [ ":create_common_sdk_nnbd" ]
+action("write_dartdoc_options") {
+  visibility = [ ":create_common_sdk" ]
   inputs = [
     "../.git/logs/HEAD",
   ]
-  output = "$root_out_dir/dart-sdk-nnbd/dartdoc_options.yaml"
+  output = "$root_out_dir/dart-sdk/dartdoc_options.yaml"
   outputs = [
     output,
   ]
@@ -1005,85 +984,85 @@
 }
 
 # This rule copies the API readme file to lib/
-copy("copy_api_readme_nnbd") {
-  visibility = [ ":create_common_sdk_nnbd" ]
+copy("copy_api_readme") {
+  visibility = [ ":create_common_sdk" ]
   sources = [
     "api_readme.md",
   ]
   outputs = [
-    "$root_out_dir/dart-sdk-nnbd/lib/api_readme.md",
+    "$root_out_dir/dart-sdk/lib/api_readme.md",
   ]
 }
 
 # Parts common to both platform and full SDKs.
-group("create_common_sdk_nnbd") {
-  visibility = [ ":create_sdk_nnbd" ]
+group("create_common_sdk") {
+  visibility = [ ":create_sdk" ]
   public_deps = [
-    ":copy_analysis_summaries_nnbd",
-    ":copy_api_readme_nnbd",
-    ":copy_dart_nnbd",
-    ":copy_dart2native_nnbd",
-    ":copy_dartdoc_files_nnbd",
-    ":copy_headers_nnbd",
-    ":copy_libraries_dart_nnbd",
-    ":copy_libraries_specification_nnbd",
-    ":copy_license_nnbd",
-    ":copy_readme_nnbd",
-    ":copy_vm_dill_files_nnbd",
-    ":write_dartdoc_options_nnbd",
-    ":write_revision_file_nnbd",
-    ":write_version_file_nnbd",
+    ":copy_analysis_summaries",
+    ":copy_api_readme",
+    ":copy_dart",
+    ":copy_dart2native",
+    ":copy_dartdoc_files",
+    ":copy_headers",
+    ":copy_libraries_dart",
+    ":copy_libraries_specification",
+    ":copy_license",
+    ":copy_readme",
+    ":copy_vm_dill_files",
+    ":write_dartdoc_options",
+    ":write_revision_file",
+    ":write_version_file",
   ]
   if (is_win) {
-    public_deps += [ ":copy_7zip_nnbd" ]
+    public_deps += [ ":copy_7zip" ]
   }
   if (target_cpu == "x64") {
     public_deps += [
-      ":copy_language_model_nnbd",
-      ":copy_libtensorflowlite_c_nnbd",
+      ":copy_language_model",
+      ":copy_libtensorflowlite_c",
     ]
   }
 }
 
 # Parts specific to the platform SDK.
-group("create_platform_sdk_nnbd") {
-  visibility = [ ":create_sdk_nnbd" ]
+group("create_platform_sdk") {
+  visibility = [ ":create_sdk" ]
   public_deps = [
-    ":copy_platform_sdk_libraries_nnbd",
-    ":copy_platform_sdk_scripts_nnbd",
-    ":copy_platform_sdk_snapshots_nnbd",
+    ":copy_platform_sdk_libraries",
+    ":copy_platform_sdk_scripts",
+    ":copy_platform_sdk_snapshots",
   ]
 }
 
 # Parts specific to the full SDK.
-group("create_full_sdk_nnbd") {
-  visibility = [ ":create_sdk_nnbd" ]
+group("create_full_sdk") {
+  visibility = [ ":create_sdk" ]
 
   public_deps = [
-    ":copy_dart2js_dill_files_nnbd",
-    ":copy_dev_compiler_sdk_nnbd",
-    ":copy_full_sdk_libraries_nnbd",
-    ":copy_full_sdk_scripts_nnbd",
-    ":copy_full_sdk_snapshots_nnbd",
+    ":copy_dart2js_dill_files",
+    ":copy_dev_compiler_sdk",
+    ":copy_full_sdk_libraries",
+    ":copy_full_sdk_scripts",
+    ":copy_full_sdk_snapshots",
   ]
 }
 
 # The main target to depend on from ../BUILD.gn
-group("create_sdk_nnbd") {
+group("create_sdk") {
   public_deps = [
-    ":create_common_sdk_nnbd",
+    ":create_common_sdk",
   ]
-  if (dart_platform_sdk_nnbd) {
-    public_deps += [ ":create_platform_sdk_nnbd" ]
+  if (dart_platform_sdk) {
+    public_deps += [ ":create_platform_sdk" ]
   } else {
-    public_deps += [ ":create_full_sdk_nnbd" ]
+    public_deps += [ ":create_full_sdk" ]
   }
 }
 
 # Same as create_sdk, but with abi version files.
-group("create_sdk_with_abi_versions_nnbd") {
+group("create_sdk_with_abi_versions") {
   public_deps = [
-    ":copy_abi_dill_files_nnbd",
-    ":create_sdk_nnbd",
+    ":copy_abi_dill_files",
+    ":create_sdk",
   ]
-}
\ No newline at end of file
+}
diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart
index f74d8dd..f1f8d00 100644
--- a/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart
+++ b/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart
@@ -100,6 +100,11 @@
   dynamic _precomputed3;
   dynamic _precomputed4;
 
+  static Rti _getPrecomputed1(Rti rti) => _castToRti(rti._precomputed1);
+  static void _setPrecomputed1(Rti rti, Rti precomputed) {
+    rti._precomputed1 = precomputed;
+  }
+
   // The Type object corresponding to this Rti.
   Object _cachedRuntimeType;
   static _Type _getCachedRuntimeType(Rti rti) =>
@@ -1497,6 +1502,10 @@
     Rti._setKind(rti, Rti.kindInterface);
     Rti._setPrimary(rti, name);
     Rti._setRest(rti, typeArguments);
+    int length = _Utils.arrayLength(typeArguments);
+    if (length > 0) {
+      Rti._setPrecomputed1(rti, _castToRti(_Utils.arrayAt(typeArguments, 0)));
+    }
     Rti._setCanonicalRecipe(rti, key);
     return _finishRti(universe, rti);
   }
@@ -2079,6 +2088,7 @@
     if (kind != Rti.kindInterface) {
       throw AssertionError('Indexed base must be an interface type');
     }
+    if (index == 1) return Rti._getPrecomputed1(environment);
     var typeArguments = Rti._getInterfaceTypeArguments(environment);
     int len = _Utils.arrayLength(typeArguments);
     if (index <= len) {
diff --git a/sdk_nnbd/lib/developer/timeline.dart b/sdk_nnbd/lib/developer/timeline.dart
index 2e5f4ec..03e360c 100644
--- a/sdk_nnbd/lib/developer/timeline.dart
+++ b/sdk_nnbd/lib/developer/timeline.dart
@@ -182,11 +182,23 @@
 /// [TimelineTask] in the other isolate.
 class TimelineTask {
   /// Create a task. The task ID will be set by the system.
-  TimelineTask() : _taskId = _getNextAsyncId() {}
+  ///
+  /// 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({TimelineTask parent})
+      : _parent = parent,
+        _taskId = _getNextAsyncId() {}
 
   /// Create a task with an explicit [taskId]. This is useful if you are
   /// passing a task from one isolate to another.
-  TimelineTask.withTaskId(int taskId) : _taskId = taskId {
+  ///
+  /// 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,
+        _taskId = taskId {
     ArgumentError.checkNotNull(taskId, 'taskId');
   }
 
@@ -197,7 +209,10 @@
     ArgumentError.checkNotNull(name, 'name');
     var block = new _AsyncBlock._(name, _taskId);
     _stack.add(block);
-    block._start(arguments);
+    block._start({
+      if (arguments != null) ...arguments,
+      if (_parent != null) 'parentId': _parent._taskId.toRadixString(16),
+    });
   }
 
   /// Emit an instant event for this task.
@@ -239,6 +254,7 @@
     return r;
   }
 
+  final TimelineTask _parent;
   final int _taskId;
   final List<_AsyncBlock> _stack = [];
 }
diff --git a/sdk_nnbd/lib/libraries.json b/sdk_nnbd/lib/libraries.json
index a9276e2..fc19bb1 100644
--- a/sdk_nnbd/lib/libraries.json
+++ b/sdk_nnbd/lib/libraries.json
@@ -143,9 +143,6 @@
         "patches": "_internal/vm/lib/convert_patch.dart",
         "uri": "convert/convert.dart"
       },
-      "profiler": {
-        "uri": "profiler/profiler.dart"
-      },
       "math": {
         "patches": "_internal/vm/lib/math_patch.dart",
         "uri": "math/math.dart"
diff --git a/sdk_nnbd/lib/libraries.yaml b/sdk_nnbd/lib/libraries.yaml
index 8d56624..7e78ad6 100644
--- a/sdk_nnbd/lib/libraries.yaml
+++ b/sdk_nnbd/lib/libraries.yaml
@@ -140,9 +140,6 @@
     nativewrappers:
       uri: "html/dartium/nativewrappers.dart"
 
-    profiler:
-      uri: "profiler/profiler.dart"
-
     cli:
       uri: "cli/cli.dart"
       patches:
diff --git a/tests/ffi/ffi.status b/tests/ffi/ffi.status
index 868f098..f2f9579 100644
--- a/tests/ffi/ffi.status
+++ b/tests/ffi/ffi.status
@@ -29,4 +29,4 @@
 *: Skip # FFI not yet supported on the arm simulator.
 
 [ $system == android ]
-*: Slow # https://github.com/dart-lang/sdk/issues/38489
+*: Pass, Slow # https://github.com/dart-lang/sdk/issues/38489
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 04f6825..e0529dd 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
@@ -35,15 +35,17 @@
   s.e1;
 //  ^^
 // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
-// [cfe] unspecified
+// [cfe] The getter 'e1' isn't defined for the class 'String'.
   E1(s).e1;
 //^^
 // [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
-// [cfe] unspecified
+//      ^
+// [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] unspecified
+//              ^
+// [cfe] Inferred 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;
@@ -57,15 +59,17 @@
   s.e2;
 //  ^^
 // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
-// [cfe] unspecified
+// [cfe] The getter 'e2' isn't defined for the class 'String'.
   E2(s).e2;
 //^^
 // [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
-// [cfe] unspecified
+//      ^
+// [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] unspecified
+//                   ^
+// [cfe] Inferred 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;
@@ -80,15 +84,15 @@
   s.f3(3);
 //  ^^
 // [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
-// [cfe] unspecified
+// [cfe] 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
-// [cfe] unspecified
+// [cfe] Inferred type argument 'int' doesn't conform to the bound 'T' of the type variable 'S' on 'E3|f3'.
   E3<String>(s).f3(3);
 //              ^^
 // [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
-// [cfe] unspecified
+// [cfe] Inferred type argument 'int' doesn't conform to the bound 'T' of the type variable 'S' on 'E3|f3'.
 
   // Inferred type int for method type parameter is ok
   i.f3(3);
@@ -100,15 +104,15 @@
   d.f3(3);
 //  ^^
 // [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
-// [cfe] unspecified
+// [cfe] 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
-// [cfe] unspecified
+// [cfe] Inferred type argument 'int' doesn't conform to the bound 'T' of the type variable 'S' on 'E3|f3'.
   E3<double>(d).f3(3);
 //              ^^
 // [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
-// [cfe] unspecified
+// [cfe] Inferred type argument 'int' doesn't conform to the bound 'T' of the type variable 'S' on 'E3|f3'.
 
   RecSolution recs = RecSolution();
   Rec<dynamic> superRec = RecSolution(); // Super-bounded type.
@@ -122,13 +126,15 @@
   superRec.e4;
 //         ^^
 // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
-// [cfe] unspecified
+// [cfe] The getter 'e4' isn't defined for the class 'Rec<dynamic>'.
   E4(superRec).e4;
 //^^
 // [analyzer] COMPILE_TIME_ERROR.COULD_NOT_INFER
-// [cfe] unspecified
+//             ^
+// [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] unspecified
+//                           ^
+// [cfe] Inferred 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_getter_setter_conflicts_test.dart b/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart
index ad98f03..f4cd928 100644
--- a/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart
+++ b/tests/language_2/extension_methods/static_extension_getter_setter_conflicts_test.dart
@@ -26,67 +26,73 @@
   c0.m1 = 0;
   // ^^
   // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
-  // [cfe] unspecified
+  // [cfe] The setter 'm1' isn't defined for the class 'C0'.
   E0(c0).m1 = 0;
   E0(c0).m1;
   //     ^^
   // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_EXTENSION_GETTER
-  // [cfe] unspecified
+  // [cfe] Getter not found: 'm1'.
 
   c0.m1 += 0;
   // ^^
   // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
-  // [cfe] unspecified
+  // [cfe] The setter 'm1' isn't defined for the class 'C0'.
 
   c0.m1++;
   // ^^
   // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
-  // [cfe] unspecified
+  // [cfe] The setter 'm1' isn't defined for the class 'C0'.
 
   c0.m2 = 0;
   c0.m2;
   // ^^
   // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
-  // [cfe] unspecified
+  // [cfe] The getter 'm2' isn't defined for the class 'C0'.
   c0.m2 += 0;
   // ^^
   // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
-  // [cfe] unspecified
+  // [cfe] The getter 'm2' isn't defined for the class 'C0'.
   c0.m2++;
   // ^^
   // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
-  // [cfe] unspecified
+  // [cfe] The getter 'm2' isn't defined for the class 'C0'.
 
   E0(c0).m2;
 
   c0[0];
   c0[0] = 0;
+  //^
+  // [cfe] The method '[]=' isn't defined for the class 'C0'.
   // ^^^^^^
   // [analyzer] unspecified
-  // [cfe] unspecified
   E0(c0)[0];
   // ^^^^^^
   // [analyzer] unspecified
-  // [cfe] unspecified
+  //    ^
+  // [cfe] Getter not found: '[]'.
   E0(c0)[0] = 0;
 
   c0[0] += 0;
+  //^
+  // [cfe] The method '[]=' isn't defined for the class 'C0'.
   // ^^^^^^
   // [analyzer] unspecified
-  // [cfe] unspecified
   c0[0]++;
+  //^
+  // [cfe] The method '[]=' isn't defined for the class 'C0'.
   // ^^^^^^
   // [analyzer] unspecified
-  // [cfe] unspecified
 
   E0(c0)[0] += 0;
   // ^^^^^^
   // [analyzer] unspecified
-  // [cfe] unspecified
+  //    ^
+  // [cfe] The method '[]' isn't defined for the class 'dynamic'.
   E0(c0)[0]++;
   // ^^^^^^
   // [analyzer] unspecified
-  // [cfe] unspecified
+  //    ^
+  // [cfe] The method '[]' isn't defined for the class 'dynamic'.
 }
 
 // Conflicting extensions.
@@ -112,29 +118,32 @@
   c1a.m1 = 0;
   //  ^^
   // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_LOCAL
-  // [cfe] unspecified
+  // [cfe] The setter 'm1' isn't defined for the class 'C1<int>'.
 
   c1a.m2;
   //  ^^
   // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
-  // [cfe] unspecified
+  // [cfe] The getter 'm2' isn't defined for the class 'C1<int>'.
 
   c1a.m2 = 0;
 
   c1a[0] = 0;
+  // ^
+  // [cfe] The method '[]=' isn't defined for the class 'C1<int>'.
   //  ^^
   // [analyzer] unspecified
-  // [cfe] unspecified
 
   c1a[0] += 0;
+  // ^
+  // [cfe] The method '[]=' isn't defined for the class 'C1<int>'.
   //  ^^
   // [analyzer] unspecified
-  // [cfe] unspecified
 
   c1a[0]++;
+  // ^
+  // [cfe] The method '[]=' isn't defined for the class 'C1<int>'.
   //  ^^
   // [analyzer] unspecified
-  // [cfe] unspecified
 
   c1a[0];
 
@@ -143,59 +152,59 @@
   c1b.m1;
   //  ^^
   // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
-  // [cfe] unspecified
+  // [cfe] The getter 'm1' isn't defined for the class 'C1<Object>'.
 
   c1b.m1 = 0;
   //  ^^
   // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
-  // [cfe] unspecified
+  // [cfe] The setter 'm1' isn't defined for the class 'C1<Object>'.
 
   c1b.m1 += 0;
   //  ^^
   // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
-  //  ^^
-  // [cfe] unspecified
-  //  ^^
-  // [cfe] unspecified
+  // [cfe] The getter 'm1' isn't defined for the class 'C1<Object>'.
+  //  ^
+  // [cfe] The setter 'm1' isn't defined for the class 'C1<Object>'.
 
   c1b.m1++;
   //  ^^
   // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
-  //  ^^
-  // [cfe] unspecified
-  //  ^^
-  // [cfe] unspecified
+  // [cfe] The getter 'm1' isn't defined for the class 'C1<Object>'.
+  //  ^
+  // [cfe] The setter 'm1' isn't defined for the class 'C1<Object>'.
 
   c1b.m2;
   //  ^^
   // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
-  // [cfe] unspecified
+  // [cfe] The getter 'm2' isn't defined for the class 'C1<Object>'.
 
   c1b[0];
+  // ^
+  // [cfe] The method '[]' isn't defined for the class 'C1<Object>'.
   //  ^^
   // [analyzer] unspecified
-  // [cfe] unspecified
 
   c1b[0] = 0;
+  // ^
+  // [cfe] The method '[]=' isn't defined for the class 'C1<Object>'.
   //  ^^
   // [analyzer] unspecified
-  // [cfe] unspecified
 
   c1b[0] += 0;
+  // ^
+  // [cfe] The method '[]' isn't defined for the class 'C1<Object>'.
+  // ^
+  // [cfe] The method '[]=' isn't defined for the class 'C1<Object>'.
   //  ^^
   // [analyzer] unspecified
-  // ^
-  // [cfe] unspecified
-  // ^
-  // [cfe] unspecified
 
   c1b[0]++;
+  // ^
+  // [cfe] The method '[]' isn't defined for the class 'C1<Object>'.
+  // ^
+  // [cfe] The method '[]=' isn't defined for the class 'C1<Object>'.
   //  ^^
   // [analyzer] unspecified
-  // ^
-  // [cfe] unspecified
-  // ^
-  // [cfe] unspecified
 }
 
 // Getter on the extension itself.
@@ -220,29 +229,32 @@
     this.m1 = 0;
     //   ^^
     // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
-    // [cfe] unspecified
+    // [cfe] The setter 'm1' isn't defined for the class 'C2'.
 
     this.m2 = 0;
     this.m2;
     //   ^^
     // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_GETTER
-    // [cfe] unspecified
+    // [cfe] The getter 'm2' isn't defined for the class 'C2'.
 
     this[0] = 0;
     this[0];
+    //  ^
+    // [cfe] The method '[]' isn't defined for the class 'C2'.
     //   ^^
     // [analyzer] unspecified
-    // [cfe] unspecified
 
     this[0] += 0;
+    //  ^
+    // [cfe] The method '[]' isn't defined for the class 'C2'.
     //   ^^
     // [analyzer] unspecified
-    // [cfe] unspecified
 
     this[0] ++;
+    //  ^
+    // [cfe] The method '[]' isn't defined for the class 'C2'.
     //   ^^
     // [analyzer] unspecified
-    // [cfe] unspecified
 
     // Check that `this.mc` refers to `C2.mc`.
     this.mc.toRadixString(16);
diff --git a/tests/language_2/extension_methods/static_extension_internal_basename_shadowing_error_test.dart b/tests/language_2/extension_methods/static_extension_internal_basename_shadowing_error_test.dart
index 4158947..297cfcd 100644
--- a/tests/language_2/extension_methods/static_extension_internal_basename_shadowing_error_test.dart
+++ b/tests/language_2/extension_methods/static_extension_internal_basename_shadowing_error_test.dart
@@ -24,44 +24,38 @@
   void test() {
     // The instance getter shadows the global setter
     topLevelSetter = topLevelSetter + 1;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'topLevelSetter'.
     topLevelSetter++;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'topLevelSetter'.
     topLevelSetter = 0;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'topLevelSetter'.
 
     // The instance getter shadows the global field setter
     topLevelField = topLevelField + 1;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'topLevelField'.
     topLevelField++;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'topLevelField'.
     topLevelField = 0;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'topLevelField'.
 
     // The instance getter shadows the global method
     topLevelMethod(4);
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^
 // [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+//                ^
+// [cfe] The method 'call' isn't defined for the class 'int'.
   }
 }
 
@@ -78,36 +72,36 @@
     topLevelGetter = topLevelGetter + 1;
 //                   ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'topLevelGetter'.
     topLevelGetter++;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'topLevelGetter'.
     topLevelGetter;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'topLevelGetter'.
     topLevelGetter = 3;
 
     // The instance setter shadows the global field getter
     topLevelField = topLevelField + 1;
 //                  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'topLevelField'.
     topLevelField++;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'topLevelField'.
     topLevelField;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'topLevelField'.
 
     // The instance setter shadows the global method
     topLevelMethod(4);
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'topLevelMethod'.
   }
 }
 
@@ -122,44 +116,38 @@
   void test() {
     // The static getter shadows the global setter
     topLevelSetter = topLevelSetter + 1;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'topLevelSetter'.
     topLevelSetter++;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'topLevelSetter'.
     topLevelSetter = 0;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'topLevelSetter'.
 
     // The static getter shadows the global field setter
     topLevelField = topLevelField + 1;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'topLevelField'.
     topLevelField++;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'topLevelField'.
     topLevelField = 0;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'topLevelField'.
 
     // The static getter shadows the global method
     topLevelMethod(4);
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^
 // [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+//                   ^
+// [cfe] The method 'call' isn't defined for the class 'int'.
   }
 }
 
@@ -176,35 +164,35 @@
     topLevelGetter = topLevelGetter + 1;
 //                   ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'topLevelGetter'.
     topLevelGetter++;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'topLevelGetter'.
     topLevelGetter;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'topLevelGetter'.
 
     // The static setter shadows the global field getter
     topLevelField = topLevelField + 1;
 //                  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'topLevelField'.
     topLevelField++;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'topLevelField'.
     topLevelField;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'topLevelField'.
 
     // The static setter shadows the global method
     topLevelMethod(4);
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'topLevelMethod'.
   }
 }
 
@@ -224,27 +212,24 @@
   void test() {
     // The instance getter shadows the other extension's setter
     extensionSetter = extensionSetter + 1;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'extensionSetter'.
     extensionSetter++;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'extensionSetter'.
     extensionSetter = 0;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'extensionSetter'.
 
     // The instance getter shadows the other extensions method
     extensionMethod(4);
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^^
 // [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+//                 ^
+// [cfe] The method 'call' isn't defined for the class 'int'.
   }
 }
 
@@ -258,27 +243,23 @@
   void test() {
     // The instance getter shadows the other extension's setter
     extensionSetter = extensionSetter + 1;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] The setter 'extensionSetter' isn't defined for the class 'A7'.
     extensionSetter++;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] The setter 'extensionSetter' isn't defined for the class 'A7'.
     extensionSetter = 0;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] The setter 'extensionSetter' isn't defined for the class 'A7'.
 
     // The instance getter shadows the other extensions method
     extensionMethod(4);
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^^
 // [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+// [cfe] 'extensionMethod' isn't a function or method and can't be invoked.
   }
 }
 
@@ -298,21 +279,21 @@
     extensionGetter = extensionGetter + 1;
 //                    ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'extensionGetter'.
     extensionGetter++;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'extensionGetter'.
     extensionGetter;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'extensionGetter'.
 
     // The instance setter shadows the other extension's method.
     extensionMethod(4);
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'extensionMethod'.
   }
 }
 
@@ -328,21 +309,21 @@
     extensionGetter = extensionGetter + 1;
 //                    ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] The getter 'extensionGetter' isn't defined for the class 'A9'.
     extensionGetter++;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] The getter 'extensionGetter' isn't defined for the class 'A9'.
     extensionGetter;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] The getter 'extensionGetter' isn't defined for the class 'A9'.
 
     // The instance setter shadows the other extension's method.
     extensionMethod(4);
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] The method 'extensionMethod' isn't defined for the class 'A9'.
   }
 }
 
@@ -362,41 +343,38 @@
   void test() {
     // The static getter shadows the other extension's setter
     extensionSetter = extensionSetter + 1;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'extensionSetter'.
     extensionSetter++;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'extensionSetter'.
     extensionSetter = 0;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'extensionSetter'.
 
     // The static field shadows the other extension's setter
     extensionFieldSetter = extensionFieldSetter + 1;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Setter not found: 'extensionFieldSetter'.
     extensionFieldSetter++;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Setter not found: 'extensionFieldSetter'.
     extensionFieldSetter = 0;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Setter not found: 'extensionFieldSetter'.
 
     // The static getter shadows the other extensions method
     extensionMethod(4);
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^^
 // [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+//                     ^
+// [cfe] The method 'call' isn't defined for the class 'int'.
   }
 }
 
@@ -411,41 +389,38 @@
   void test() {
     // The static getter shadows the other extension's setter
     extensionSetter = extensionSetter + 1;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'extensionSetter'.
     extensionSetter++;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'extensionSetter'.
     extensionSetter = 0;
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.ASSIGNMENT_TO_FINAL_NO_SETTER
+// [cfe] Setter not found: 'extensionSetter'.
 
     // The static field shadows the other extension's setter
     extensionFieldSetter = extensionFieldSetter + 1;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Setter not found: 'extensionFieldSetter'.
     extensionFieldSetter++;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Setter not found: 'extensionFieldSetter'.
     extensionFieldSetter = 0;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Setter not found: 'extensionFieldSetter'.
 
     // The static getter shadows the other extensions method
     extensionMethod(4);
-//  ^^
-// [cfe] unspecified
 //  ^^^^^^^^^^^^^^^
 // [analyzer] STATIC_TYPE_WARNING.INVOCATION_OF_NON_FUNCTION
+//                 ^
+// [cfe] The method 'call' isn't defined for the class 'int'.
   }
 }
 
@@ -465,21 +440,21 @@
     extensionGetter = extensionGetter + 1;
 //                    ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'extensionGetter'.
     extensionGetter++;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'extensionGetter'.
     extensionGetter;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'extensionGetter'.
 
     // The static setter shadows the other extension's method.
     extensionMethod(4);
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'extensionMethod'.
   }
 }
 
@@ -495,21 +470,21 @@
     extensionGetter = extensionGetter + 1;
 //                    ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'extensionGetter'.
     extensionGetter++;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'extensionGetter'.
     extensionGetter;
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'extensionGetter'.
 
     // The static setter shadows the other extension's method.
     extensionMethod(4);
 //  ^^
 // [analyzer] unspecified
-// [cfe] unspecified
+// [cfe] Getter not found: 'extensionMethod'.
   }
 }
 
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 6e4ebdfb..8189ae8 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
@@ -10,7 +10,7 @@
 extension E1<T, T> on int {
 //              ^
 // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
-// [cfe] unspecified
+// [cfe] A type variable can't have the same name as another.
 }
 
 extension E2 on int {}
@@ -19,27 +19,27 @@
 extension E2 on int {}
 //        ^^
 // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
-// [cfe] unspecified
+// [cfe] 'E2' is already declared in this scope.
 
 class E2 {}
 //    ^^
 // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
-// [cfe] unspecified
+// [cfe] 'E2' is already declared in this scope.
 
 typedef E2 = int Function(int);
 //      ^^
 // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
-// [cfe] unspecified
+// [cfe] 'E2' is already declared in this scope.
 
 void E2(int x) {}
 //   ^^
 // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
-// [cfe] unspecified
+// [cfe] 'E2' is already declared in this scope.
 
 int E2 = 3;
 //  ^^
 // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
-// [cfe] unspecified
+// [cfe] 'E2' is already declared in this scope.
 
 ////////////////////////////////////////////////////////////////////
 // It is an error to have two static members with the same base name
@@ -64,23 +64,23 @@
   static int method() => 0;
   //         ^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
-  // [cfe] unspecified
+  // [cfe] 'method' is already declared in this scope.
   static int get property => 1;
   //             ^^^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
-  // [cfe] unspecified
+  // [cfe] 'property' is already declared in this scope.
   static void set property(int value) {}
   //              ^^^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
-  // [cfe] unspecified
+  // [cfe] 'property' is already declared in this scope.
   static int field = 3;
   //         ^^^^^
   // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
-  // [cfe] unspecified
+  // [cfe] 'field' is already declared in this scope.
   static int get field2 => 1;
   //             ^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
-  // [cfe] unspecified
+  // [cfe] 'field2' is already declared in this scope.
   static void set field2(int value) {}
   //              ^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
@@ -96,15 +96,15 @@
   int method() => 0;
   //  ^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
-  // [cfe] unspecified
+  // [cfe] 'method' is already declared in this scope.
   int get property => 1;
   //      ^^^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
-  // [cfe] unspecified
+  // [cfe] 'property' is already declared in this scope.
   void set property(int value) {}
   //       ^^^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
-  // [cfe] unspecified
+  // [cfe] 'property' is already declared in this scope.
 }
 
 // Check static members colliding with static members (of the same kind).
@@ -127,20 +127,20 @@
   static int field = 3;
   //         ^^^^^
   // [analyzer] COMPILE_TIME_ERROR.EXTENSION_CONFLICTING_STATIC_AND_INSTANCE
-  // [cfe] unspecified
+  // [cfe] Conflicts with setter 'field'.
   static int field2 = 3;
   //         ^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.EXTENSION_CONFLICTING_STATIC_AND_INSTANCE
 
   int method() => 0;
-  //  ^^^^^^
-  // [cfe] unspecified
+  //  ^
+  // [cfe] 'method' is already declared in this scope.
   int get property => 1;
-  //      ^^^^^^^^
-  // [cfe] unspecified
+  //      ^
+  // [cfe] 'property' is already declared in this scope.
   void set property(int value) {}
-  //       ^^^^^^^^
-  // [cfe] unspecified
+  //       ^
+  // [cfe] 'property' is already declared in this scope.
   void set property2(int value) {}
   //       ^^^^^^^^^
   // [cfe] unspecified
@@ -148,11 +148,11 @@
   //      ^^^^^^^^^
   // [cfe] unspecified
   void set field(int value) {}
-  //       ^^^^^
-  // [cfe] unspecified
+  //       ^
+  // [cfe] Conflicts with member 'field'.
   int get field2 => 1;
-  //      ^^^^^^
-  // [cfe] unspecified
+  //      ^
+  // [cfe] 'field2' is already declared in this scope.
 }
 
 // Check a static method colliding with a static getter.
@@ -161,18 +161,18 @@
   static int get method => 1;
   //             ^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
-  // [cfe] unspecified
+  // [cfe] 'method' is already declared in this scope.
 }
 
 // Check a static method colliding with a static setter.
 extension E7 on int {
   static int method() => 0;
-  //         ^^^^^^
-  // [cfe] unspecified
+  //         ^
+  // [cfe] Conflicts with setter 'method'.
   static void set method(int value) {}
   //              ^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
-  // [cfe] unspecified
+  // [cfe] Conflicts with member 'method'.
 }
 
 // Check a static method colliding with a static field.
@@ -181,7 +181,7 @@
   static int method = 3;
   //         ^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
-  // [cfe] unspecified
+  // [cfe] 'method' is already declared in this scope.
 }
 
 // Check an instance method colliding with an instance getter.
@@ -190,7 +190,7 @@
   int get method => 1;
   //      ^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.DUPLICATE_DEFINITION
-  // [cfe] unspecified
+  // [cfe] 'method' is already declared in this scope.
 }
 
 // Check an instance method colliding with an instance setter.
@@ -208,8 +208,8 @@
   //         ^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.EXTENSION_CONFLICTING_STATIC_AND_INSTANCE
   int get method => 1;
-  //      ^^^^^^
-  // [cfe] unspecified
+  //      ^
+  // [cfe] 'method' is already declared in this scope.
 }
 
 // Check a static method colliding with an instance setter.
@@ -217,9 +217,8 @@
   static int method() => 0;
   //         ^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.EXTENSION_CONFLICTING_STATIC_AND_INSTANCE
-  void set method(int value) {}
-  //       ^^^^^^
   // [cfe] unspecified
+  void set method(int value) {}
 }
 
 // Check an instance method colliding with a static getter.
@@ -228,7 +227,7 @@
   static int get method => 1;
   //             ^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.EXTENSION_CONFLICTING_STATIC_AND_INSTANCE
-  // [cfe] unspecified
+  // [cfe] 'method' is already declared in this scope.
 }
 
 // Check an instance method colliding with a static setter.
@@ -246,7 +245,7 @@
   static int method = 3;
   //         ^^^^^^
   // [analyzer] COMPILE_TIME_ERROR.EXTENSION_CONFLICTING_STATIC_AND_INSTANCE
-  // [cfe] unspecified
+  // [cfe] 'method' is already declared in this scope.
 }
 
 void main() {}
diff --git a/tests/language_2/extension_methods/static_extension_internal_resolution_3_error_test.dart b/tests/language_2/extension_methods/static_extension_internal_resolution_3_error_test.dart
index 8d47a88..01886be 100644
--- a/tests/language_2/extension_methods/static_extension_internal_resolution_3_error_test.dart
+++ b/tests/language_2/extension_methods/static_extension_internal_resolution_3_error_test.dart
@@ -94,27 +94,23 @@
     // Prefixed globals are ambiguous
     {
       bool t0 = this.fieldInGlobalScope;
-      //             ^^^
-      // [cfe] unspecified
       //             ^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The getter 'fieldInGlobalScope' isn't defined for the class 'A'.
       checkExtensionValue(t0);
       bool t1 = this.getterInGlobalScope;
-      //             ^^^
-      // [cfe] unspecified
       //             ^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The getter 'getterInGlobalScope' isn't defined for the class 'A'.
       checkExtensionValue(t1);
       this.setterInGlobalScope = extensionValue;
-      //   ^^^
-      // [cfe] unspecified
       //   ^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The setter 'setterInGlobalScope' isn't defined for the class 'A'.
       bool t2 = this.methodInGlobalScope();
-      //             ^^^
-      // [cfe] unspecified
       //             ^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The method 'methodInGlobalScope' isn't defined for the class 'A'.
       checkExtensionValue(t2);
     }
 
@@ -142,27 +138,23 @@
     // Prefixed globals are ambiguous
     {
       bool t0 = self.fieldInGlobalScope;
-      //             ^^^
-      // [cfe] unspecified
       //             ^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The getter 'fieldInGlobalScope' isn't defined for the class 'A'.
       checkExtensionValue(t0);
       bool t1 = self.getterInGlobalScope;
-      //             ^^^
-      // [cfe] unspecified
       //             ^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The getter 'getterInGlobalScope' isn't defined for the class 'A'.
       checkExtensionValue(t1);
       self.setterInGlobalScope = extensionValue;
-      //   ^^^
-      // [cfe] unspecified
       //   ^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The setter 'setterInGlobalScope' isn't defined for the class 'A'.
       bool t2 = self.methodInGlobalScope();
-      //             ^^^
-      // [cfe] unspecified
       //             ^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The method 'methodInGlobalScope' isn't defined for the class 'A'.
       checkExtensionValue(t2);
     }
 
@@ -230,27 +222,23 @@
   // Global names come from both extensions and hence are ambiguous.
   {
     bool t0 = a.fieldInGlobalScope;
-    //          ^^^
-    // [cfe] unspecified
     //          ^^^^^^^^^^^^^^^^^^
     // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+    // [cfe] The getter 'fieldInGlobalScope' isn't defined for the class 'A'.
     checkExtensionValue(t0);
     bool t1 = a.getterInGlobalScope;
-    //          ^^^
-    // [cfe] unspecified
     //          ^^^^^^^^^^^^^^^^^^^
     // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+    // [cfe] The getter 'getterInGlobalScope' isn't defined for the class 'A'.
     checkExtensionValue(t1);
     a.setterInGlobalScope = extensionValue;
     //^^^^^^^^^^^^^^^^^^^
     // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
-    // ^^^
-    // [cfe] unspecified
+    // [cfe] The setter 'setterInGlobalScope' isn't defined for the class 'A'.
     bool t2 = a.methodInGlobalScope();
-    //          ^^^
-    // [cfe] unspecified
     //          ^^^^^^^^^^^^^^^^^^^
     // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+    // [cfe] The method 'methodInGlobalScope' isn't defined for the class 'A'.
     checkExtensionValue(t2);
   }
 
diff --git a/tests/language_2/extension_methods/static_extension_internal_resolution_4_error_test.dart b/tests/language_2/extension_methods/static_extension_internal_resolution_4_error_test.dart
index b8e80b1..6842e6b 100644
--- a/tests/language_2/extension_methods/static_extension_internal_resolution_4_error_test.dart
+++ b/tests/language_2/extension_methods/static_extension_internal_resolution_4_error_test.dart
@@ -94,27 +94,23 @@
     // Prefixed globals are ambiguous
     {
       bool t0 = this.fieldInGlobalScope;
-      //             ^^^
-      // [cfe] unspecified
       //             ^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The getter 'fieldInGlobalScope' isn't defined for the class 'A'.
       checkExtensionValue(t0);
       bool t1 = this.getterInGlobalScope;
-      //             ^^^
-      // [cfe] unspecified
       //             ^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The getter 'getterInGlobalScope' isn't defined for the class 'A'.
       checkExtensionValue(t1);
       this.setterInGlobalScope = extensionValue;
-      //   ^^^
-      // [cfe] unspecified
       //   ^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The setter 'setterInGlobalScope' isn't defined for the class 'A'.
       bool t2 = this.methodInGlobalScope();
-      //             ^^^
-      // [cfe] unspecified
       //             ^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The method 'methodInGlobalScope' isn't defined for the class 'A'.
       checkExtensionValue(t2);
     }
 
@@ -127,27 +123,23 @@
     // Extension members are ambigious.
     {
       bool t0 = this.fieldInExtensionScope;
-      //             ^^^
-      // [cfe] unspecified
       //             ^^^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The getter 'fieldInExtensionScope' isn't defined for the class 'A'.
       checkExtensionValue(t0);
       bool t1 = this.getterInExtensionScope;
-      //             ^^^
-      // [cfe] unspecified
       //             ^^^^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The getter 'getterInExtensionScope' isn't defined for the class 'A'.
       checkExtensionValue(t1);
       this.setterInExtensionScope = extensionValue;
-      //   ^^^
-      // [cfe] unspecified
       //   ^^^^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The setter 'setterInExtensionScope' isn't defined for the class 'A'.
       bool t2 = this.methodInExtensionScope();
-      //             ^^^
-      // [cfe] unspecified
       //             ^^^^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The method 'methodInExtensionScope' isn't defined for the class 'A'.
       checkExtensionValue(t2);
     }
 
@@ -164,27 +156,23 @@
     // Prefixed globals are ambiguous
     {
       bool t0 = self.fieldInGlobalScope;
-      //             ^^^
-      // [cfe] unspecified
       //             ^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The getter 'fieldInGlobalScope' isn't defined for the class 'A'.
       checkExtensionValue(t0);
       bool t1 = self.getterInGlobalScope;
-      //             ^^^
-      // [cfe] unspecified
       //             ^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The getter 'getterInGlobalScope' isn't defined for the class 'A'.
       checkExtensionValue(t1);
       self.setterInGlobalScope = extensionValue;
-      //   ^^^
-      // [cfe] unspecified
       //   ^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The setter 'setterInGlobalScope' isn't defined for the class 'A'.
       bool t2 = self.methodInGlobalScope();
-      //             ^^^
-      // [cfe] unspecified
       //             ^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The method 'methodInGlobalScope' isn't defined for the class 'A'.
       checkExtensionValue(t2);
     }
 
@@ -197,27 +185,23 @@
     // Extension members are ambigious.
     {
       bool t0 = self.fieldInExtensionScope;
-      //             ^^^
-      // [cfe] unspecified
       //             ^^^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The getter 'fieldInExtensionScope' isn't defined for the class 'A'.
       checkExtensionValue(t0);
       bool t1 = self.getterInExtensionScope;
-      //             ^^^
-      // [cfe] unspecified
       //             ^^^^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The getter 'getterInExtensionScope' isn't defined for the class 'A'.
       checkExtensionValue(t1);
       self.setterInExtensionScope = extensionValue;
-      //   ^^^
-      // [cfe] unspecified
       //   ^^^^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The setter 'setterInExtensionScope' isn't defined for the class 'A'.
       bool t2 = self.methodInExtensionScope();
-      //             ^^^
-      // [cfe] unspecified
       //             ^^^^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The method 'methodInExtensionScope' isn't defined for the class 'A'.
       checkExtensionValue(t2);
     }
 
@@ -252,33 +236,29 @@
     // Extension members are ambiguous
     {
       bool t0 = fieldInExtensionScope;
-      //        ^^^
-      // [cfe] unspecified
       //        ^^^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The getter 'fieldInExtensionScope' isn't defined for the class 'B'.
       //        ^^^^^^^^^^^^^^^^^^^^^
       // [analyzer] STATIC_WARNING.UNDEFINED_IDENTIFIER
       checkExtensionValue(t0);
       bool t1 = getterInExtensionScope;
-      //        ^^^
-      // [cfe] unspecified
       //        ^^^^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The getter 'getterInExtensionScope' isn't defined for the class 'B'.
       //        ^^^^^^^^^^^^^^^^^^^^^^
       // [analyzer] STATIC_WARNING.UNDEFINED_IDENTIFIER
       checkExtensionValue(t1);
       setterInExtensionScope = extensionValue;
 //    ^^^^^^^^^^^^^^^^^^^^^^
 // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+// [cfe] The setter 'setterInExtensionScope' isn't defined for the class 'B'.
 //    ^^^^^^^^^^^^^^^^^^^^^^
 // [analyzer] STATIC_WARNING.UNDEFINED_IDENTIFIER
-//              ^^^
-// [cfe] unspecified
       bool t2 = methodInExtensionScope();
-      //        ^^^
-      // [cfe] unspecified
       //        ^^^^^^^^^^^^^^^^^^^^^^
       // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+      // [cfe] The method 'methodInExtensionScope' isn't defined for the class 'B'.
       //        ^^^^^^^^^^^^^^^^^^^^^^
       // [analyzer] STATIC_TYPE_WARNING.UNDEFINED_METHOD
       checkExtensionValue(t2);
@@ -303,27 +283,23 @@
   // Global names come from both extensions and hence are ambiguous.
   {
     bool t0 = a.fieldInGlobalScope;
-    //          ^^^
-    // [cfe] unspecified
     //          ^^^^^^^^^^^^^^^^^^
     // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+    // [cfe] The getter 'fieldInGlobalScope' isn't defined for the class 'A'.
     checkExtensionValue(t0);
     bool t1 = a.getterInGlobalScope;
-    //          ^^^
-    // [cfe] unspecified
     //          ^^^^^^^^^^^^^^^^^^^
     // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+    // [cfe] The getter 'getterInGlobalScope' isn't defined for the class 'A'.
     checkExtensionValue(t1);
     a.setterInGlobalScope = extensionValue;
     //^^^^^^^^^^^^^^^^^^^
     // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
-    // ^^^
-    // [cfe] unspecified
+    // [cfe] The setter 'setterInGlobalScope' isn't defined for the class 'A'.
     bool t2 = a.methodInGlobalScope();
-    //          ^^^
-    // [cfe] unspecified
     //          ^^^^^^^^^^^^^^^^^^^
     // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+    // [cfe] The method 'methodInGlobalScope' isn't defined for the class 'A'.
     checkExtensionValue(t2);
   }
 
@@ -336,27 +312,23 @@
   // Extension members are ambiguous
   {
     bool t0 = a.fieldInExtensionScope;
-    //          ^^^
-    // [cfe] unspecified
     //          ^^^^^^^^^^^^^^^^^^^^^
     // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+    // [cfe] The getter 'fieldInExtensionScope' isn't defined for the class 'A'.
     checkExtensionValue(t0);
     bool t1 = a.getterInExtensionScope;
-    //          ^^^
-    // [cfe] unspecified
     //          ^^^^^^^^^^^^^^^^^^^^^^
     // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+    // [cfe] The getter 'getterInExtensionScope' isn't defined for the class 'A'.
     checkExtensionValue(t1);
     a.setterInExtensionScope = extensionValue;
     //^^^^^^^^^^^^^^^^^^^^^^
     // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
-    // ^^^
-    // [cfe] unspecified
+    // [cfe] The setter 'setterInExtensionScope' isn't defined for the class 'A'.
     bool t2 = a.methodInExtensionScope();
-    //          ^^^
-    // [cfe] unspecified
     //          ^^^^^^^^^^^^^^^^^^^^^^
     // [analyzer] COMPILE_TIME_ERROR.AMBIGUOUS_EXTENSION_MEMBER_ACCESS
+    // [cfe] The method 'methodInExtensionScope' isn't defined for the class 'A'.
     checkExtensionValue(t2);
   }
 
diff --git a/tests/language_2/extension_methods/static_extension_internal_resolution_6_error_test.dart b/tests/language_2/extension_methods/static_extension_internal_resolution_6_error_test.dart
index c7e3949..de842c8 100644
--- a/tests/language_2/extension_methods/static_extension_internal_resolution_6_error_test.dart
+++ b/tests/language_2/extension_methods/static_extension_internal_resolution_6_error_test.dart
@@ -32,8 +32,7 @@
     T y = self;
     //    ^^^^
     // [analyzer] STATIC_TYPE_WARNING.INVALID_ASSIGNMENT
-    //     ^^^
-    // [cfe] unspecified
+    // [cfe] A value of type '#T' can't be assigned to a variable of type 'T'.
   }
 
   void castToShadowedTypeParam<T>() {
@@ -82,20 +81,20 @@
 
   // Invalid to overlap the static and extension scopes
   bool get fieldInInstanceScope => extensionValue;
-  //       ^^^
-  // [cfe] unspecified
+  //       ^
+  // [cfe] 'fieldInInstanceScope' is already declared in this scope.
   bool get getterInInstanceScope => extensionValue;
-  //       ^^^
-  // [cfe] unspecified
+  //       ^
+  // [cfe] 'getterInInstanceScope' is already declared in this scope.
   set setterInInstanceScope(bool x) {
-    //^^^
-    // [cfe] unspecified
+    //^
+    // [cfe] 'setterInInstanceScope' is already declared in this scope.
     checkExtensionValue(x);
   }
 
   bool methodInInstanceScope() => extensionValue;
-  //   ^^^
-  // [cfe] unspecified
+  //   ^
+  // [cfe] 'methodInInstanceScope' is already declared in this scope.
 
   void testNakedIdentifiers() {
     // Symbols in the global scope and the local static scope resolve to
diff --git a/tests/language_2/variance/variance_in_field_test.dart b/tests/language_2/variance/variance_in_field_test.dart
new file mode 100644
index 0000000..2b60fbb
--- /dev/null
+++ b/tests/language_2/variance/variance_in_field_test.dart
@@ -0,0 +1,56 @@
+// 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 various fields for the `in` variance modifier.
+
+// SharedOptions=--enable-experiment=variance
+
+import "package:expect/expect.dart";
+
+typedef Int2Void = void Function(int);
+
+class A<in T> {
+  void set a(T value) => value;
+  final void Function(T) b = (T val) {
+    Expect.equals(2, val);
+  };
+  A<T> get c => this;
+}
+
+mixin BMixin<in T> {
+  void set a(T value) => value;
+  final void Function(T) b = (T val) {
+    Expect.equals(2, val);
+  };
+  BMixin<T> get c => this;
+}
+
+class B with BMixin<int> {}
+
+void testClass() {
+  A<int> a = new A();
+
+  a.a = 2;
+
+  Expect.type<Int2Void>(a.b);
+  a.b(2);
+
+  a.c.a = 2;
+}
+
+void testMixin() {
+  B b = new B();
+
+  b.a = 2;
+
+  Expect.type<Int2Void>(b.b);
+  b.b(2);
+
+  b.c.a = 2;
+}
+
+main() {
+  testClass();
+  testMixin();
+}
diff --git a/tests/language_2/variance/variance_in_method_test.dart b/tests/language_2/variance/variance_in_method_test.dart
new file mode 100644
index 0000000..36a6d98
--- /dev/null
+++ b/tests/language_2/variance/variance_in_method_test.dart
@@ -0,0 +1,141 @@
+// 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 method signatures and return types for the `in` variance modifier.
+
+// SharedOptions=--enable-experiment=variance
+
+import "package:expect/expect.dart";
+
+typedef Cov<T> = T Function();
+typedef Contra<T> = void Function(T);
+
+class A<in T> {
+  void method1(T x) {}
+  void method2(Cov<T> x) {}
+  Contra<T> method3() {
+    return (T val) {
+      Expect.equals(2, val);
+    };
+  }
+
+  void method4(Cov<Cov<T>> x) {}
+  Contra<Cov<T>> method5() {
+    return (Cov<T> method) {
+      Expect.type<Cov<T>>(method);
+    };
+  }
+  Cov<Contra<T>> method6() {
+    return () {
+      return (T x) {
+        Expect.equals(2, x);
+      };
+    };
+  }
+  void method7(Contra<Contra<T>> x) {}
+}
+
+mixin BMixin<in T> {
+  void method1(T x) {}
+  void method2(Cov<T> x) {}
+  Contra<T> method3() {
+    return (T val) {
+      Expect.equals(2, val);
+    };
+  }
+
+  void method4(Cov<Cov<T>> x) {}
+  Contra<Cov<T>> method5() {
+    return (Cov<T> method) {
+      Expect.type<Cov<T>>(method);
+    };
+  }
+  Cov<Contra<T>> method6() {
+    return () {
+      return (T x) {
+        Expect.equals(2, x);
+      };
+    };
+  }
+  void method7(Contra<Contra<T>> x) {}
+}
+
+class B with BMixin<int> {}
+
+class C<in T> {
+  void method1(Contra<A<T>> x) {}
+  A<T> method2() {
+    return A<T>();
+  }
+}
+
+void testClass() {
+  A<int> a = new A();
+
+  a.method1(2);
+
+  a.method2(() => 2);
+
+  Expect.type<Contra<int>>(a.method3());
+  Contra<int> method3Function = a.method3();
+  method3Function(2);
+
+  a.method4(() {
+    return () => 2;
+  });
+
+  Expect.type<Contra<Cov<int>>>(a.method5());
+  Contra<Cov<int>> method5Function = a.method5();
+  method5Function(() => 2);
+
+  Expect.type<Cov<Contra<int>>>(a.method6());
+  Cov<Contra<int>> method6Function = a.method6();
+  Expect.type<Contra<int>>(method6Function());
+  Contra<int> method6NestedFunction = method6Function();
+  method6NestedFunction(2);
+
+  a.method7((Contra<int> x) {});
+}
+
+void testMixin() {
+  B b = new B();
+
+  b.method1(2);
+
+  b.method2(() => 2);
+
+  Expect.type<Contra<int>>(b.method3());
+  Contra<int> method3Return = b.method3();
+  method3Return(2);
+
+  b.method4(() {
+    return () => 2;
+  });
+
+  Expect.type<Contra<Cov<int>>>(b.method5());
+  Contra<Cov<int>> method5Return = b.method5();
+  method5Return(() => 2);
+
+  Expect.type<Cov<Contra<int>>>(b.method6());
+  Cov<Contra<int>> method6Function = b.method6();
+  Expect.type<Contra<int>>(method6Function());
+  Contra<int> method6NestedFunction = method6Function();
+  method6NestedFunction(2);
+
+  b.method7((Contra<int> x) {});
+}
+
+void testClassInMethods() {
+  C<int> c = new C();
+
+  c.method1((A<int> x) {});
+
+  Expect.type<A<int>>(c.method2());
+}
+
+main() {
+  testClass();
+  testMixin();
+  testClassInMethods();
+}
diff --git a/tests/language_2/variance/variance_inout_field_test.dart b/tests/language_2/variance/variance_inout_field_test.dart
new file mode 100644
index 0000000..58fe155
--- /dev/null
+++ b/tests/language_2/variance/variance_inout_field_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.
+
+// Tests various fields for the `inout` variance modifier.
+
+// SharedOptions=--enable-experiment=variance
+
+import "package:expect/expect.dart";
+
+typedef Void2Int = int Function();
+typedef Int2Void = void Function(int);
+
+class A<inout T> {
+  T a;
+  final T b = null;
+  final T Function() c = () => null;
+  final void Function(T) d = (T val) {
+    Expect.equals(2, val);
+  };
+  A<T> get e => this;
+}
+
+mixin BMixin<inout T> {
+  T a;
+  final T b = null;
+  final T Function() c = () => null;
+  final void Function(T) d = (T val) {
+    Expect.equals(2, val);
+  };
+  BMixin<T> get e => this;
+}
+
+class B with BMixin<int> {}
+
+void testClass() {
+  A<int> a = new A();
+
+  a.a = 2;
+  Expect.equals(2, a.a);
+
+  Expect.isNull(a.b);
+
+  Expect.type<Void2Int>(a.c);
+  Expect.isNull(a.c());
+
+  Expect.type<Int2Void>(a.d);
+  a.d(2);
+
+  a.e.a = 3;
+}
+
+void testMixin() {
+  B b = new B();
+
+  b.a = 2;
+  Expect.equals(2, b.a);
+
+  Expect.isNull(b.b);
+
+  Expect.type<Void2Int>(b.c);
+  Expect.isNull(b.c());
+
+  Expect.type<Int2Void>(b.d);
+  b.d(2);
+
+  b.e.a = 3;
+}
+
+main() {
+  testClass();
+  testMixin();
+}
diff --git a/tests/language_2/variance/variance_inout_method_test.dart b/tests/language_2/variance/variance_inout_method_test.dart
new file mode 100644
index 0000000..e167928
--- /dev/null
+++ b/tests/language_2/variance/variance_inout_method_test.dart
@@ -0,0 +1,152 @@
+// 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 method signatures and return types for the `inout` variance modifier.
+
+// SharedOptions=--enable-experiment=variance
+
+import "package:expect/expect.dart";
+
+typedef Cov<T> = T Function();
+typedef Contra<T> = void Function(T);
+Cov<int> covFunction = () => 2;
+Contra<int> contraFunction = (int val) {};
+Cov<num> covFunctionNum = () => 2;
+Contra<num> contraFunctionNum = (num val) {};
+
+class A<inout T> {
+  // Contravariant positions
+  void method1(T x) {}
+  void method2(Cov<T> x) {}
+  Contra<T> method3() {
+    return (T val) {
+      Expect.equals(2, val);
+    };
+  }
+
+  // Covariant positions
+  T method4() => null;
+  void method5(Contra<T> x) {}
+  Cov<T> method6() {
+    return () => null;
+  }
+
+  // Invariant member signatures
+  T method7(T x) => x;
+  Contra<T> method8(Contra<T> x) => x;
+  Cov<T> method9(Cov<T> x) => x;
+
+  T method10<S extends T>(S x) => x;
+}
+
+mixin BMixin<inout T> {
+  // Contravariant positions
+  void method1(T x) {}
+  void method2(Cov<T> x) {}
+  Contra<T> method3() {
+    return (T val) {
+      Expect.equals(2, val);
+    };
+  }
+
+  // Covariant positions
+  T method4() => null;
+  void method5(Contra<T> x) {}
+  Cov<T> method6() {
+    return () => null;
+  }
+
+  // Invariant member signatures
+  T method7(T x) => x;
+  Contra<T> method8(Contra<T> x) => x;
+  Cov<T> method9(Cov<T> x) => x;
+
+  T method10<S extends T>(S x) => x;
+}
+
+class B with BMixin<num> {}
+
+class C<inout T> {
+  void method1(Contra<A<T>> x) {}
+  void method2(Cov<A<T>> x) {}
+  A<T> method3() {
+    return A<T>();
+  }
+}
+
+void testClass() {
+  A<int> a = new A();
+
+  a.method1(2);
+
+  a.method2(() => 2);
+
+  Expect.type<Contra<int>>(a.method3());
+  Contra<int> method3Function = a.method3();
+  method3Function(2);
+
+  Expect.isNull(a.method4());
+
+  a.method5((int val) {});
+
+  Expect.type<Cov<int>>(a.method6());
+  Cov<int> method6Function = a.method6();
+  Expect.isNull(method6Function());
+
+  Expect.equals(3, a.method7(3));
+
+  Expect.type<Contra<int>>(a.method8(contraFunction));
+  Expect.equals(contraFunction, a.method8(contraFunction));
+
+  Expect.type<Cov<int>>(a.method9(covFunction));
+  Expect.equals(covFunction, a.method9(covFunction));
+
+  A<num> aa = new A();
+  Expect.type<num>(aa.method10(3));
+}
+
+void testMixin() {
+  B b = new B();
+
+  b.method1(2);
+
+  b.method2(() => 2);
+
+  Expect.type<Contra<num>>(b.method3());
+  Contra<num> method3Function = b.method3();
+  method3Function(2);
+
+  Expect.isNull(b.method4());
+
+  b.method5((num val) {});
+
+  Expect.type<Cov<num>>(b.method6());
+  Cov<num> method6Function = b.method6();
+  Expect.isNull(method6Function());
+
+  Expect.equals(3, b.method7(3));
+
+  Expect.type<Contra<num>>(b.method8(contraFunctionNum));
+  Expect.equals(contraFunctionNum, b.method8(contraFunctionNum));
+
+  Expect.type<Cov<num>>(b.method9(covFunctionNum));
+  Expect.equals(covFunctionNum, b.method9(covFunctionNum));
+
+  Expect.type<num>(b.method10(3));
+}
+
+void testClassInMethods() {
+  C<int> c = new C();
+
+  c.method1((A<int> x) {});
+  c.method2(() => null);
+
+  Expect.type<A<int>>(c.method3());
+}
+
+main() {
+  testClass();
+  testMixin();
+  testClassInMethods();
+}
diff --git a/tests/language_2/variance/variance_out_field_test.dart b/tests/language_2/variance/variance_out_field_test.dart
new file mode 100644
index 0000000..f39945f
--- /dev/null
+++ b/tests/language_2/variance/variance_out_field_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 various fields for the `out` variance modifier.
+
+// SharedOptions=--enable-experiment=variance
+
+import "package:expect/expect.dart";
+
+typedef Void2Int = int Function();
+
+class A<out T> {
+  final T a = null;
+  final T Function() b = () => null;
+  T get c => null;
+  A<T> get d => this;
+}
+
+mixin BMixin<out T> {
+  final T a = null;
+  final T Function() b = () => null;
+  T get c => null;
+  BMixin<T> get d => this;
+}
+
+class B with BMixin<int> {}
+
+void testClass() {
+  A<int> a = new A();
+
+  Expect.isNull(a.a);
+
+  Expect.type<Void2Int>(a.b);
+  Expect.isNull(a.b());
+
+  Expect.isNull(a.c);
+
+  Expect.isNull(a.d.a);
+}
+
+void testMixin() {
+  B b = new B();
+
+  Expect.isNull(b.a);
+
+  Expect.type<Void2Int>(b.b);
+  Expect.isNull(b.b());
+
+  Expect.isNull(b.c);
+
+  Expect.isNull(b.d.a);
+}
+
+main() {
+  testClass();
+  testMixin();
+}
diff --git a/tests/language_2/variance/variance_out_method_test.dart b/tests/language_2/variance/variance_out_method_test.dart
new file mode 100644
index 0000000..0b0e0ff
--- /dev/null
+++ b/tests/language_2/variance/variance_out_method_test.dart
@@ -0,0 +1,141 @@
+// 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 method signatures and return types for the `out` variance modifier.
+
+// SharedOptions=--enable-experiment=variance
+
+import "package:expect/expect.dart";
+
+typedef Cov<T> = T Function();
+typedef Contra<T> = void Function(T);
+
+class A<out T> {
+  // TODO (kallentu): Come NNBD, change `T` to `T?`
+  T method1() => null;
+  void method2(Contra<T> x) {}
+  Cov<T> method3() {
+    return () => null;
+  }
+
+  void method4(Contra<Cov<T>> x) {}
+  void method5(Cov<Contra<T>> x) {}
+  Contra<Contra<T>> method6() {
+    return (Contra<T> x) {
+      Expect.type<Contra<T>>(x);
+    };
+  }
+
+  Cov<Cov<T>> method7() {
+    return () {
+      return () => null;
+    };
+  }
+}
+
+mixin BMixin<out T> {
+  // TODO (kallentu): Come NNBD, change `T` to `T?`
+  T method1() => null;
+  void method2(Contra<T> x) {}
+  Cov<T> method3() {
+    return () => null;
+  }
+
+  void method4(Contra<Cov<T>> x) {}
+  void method5(Cov<Contra<T>> x) {}
+  Contra<Contra<T>> method6() {
+    return (Contra<T> x) {
+      Expect.type<Contra<T>>(x);
+    };
+  }
+
+  Cov<Cov<T>> method7() {
+    return () {
+      return () => null;
+    };
+  }
+}
+
+class B with BMixin<int> {}
+
+class C<out T> {
+  void method1(Contra<A<T>> x) {}
+  A<T> method2() {
+    return A<T>();
+  }
+}
+
+void testClass() {
+  A<int> a = new A();
+
+  Expect.isNull(a.method1());
+
+  a.method2((int x) {
+    Expect.equals(2, x);
+  });
+
+  Expect.type<Cov<int>>(a.method3());
+  Cov<int> method3Function = a.method3();
+  Expect.isNull(method3Function());
+
+  a.method4((Cov<int> x) {});
+
+  a.method5(() {
+    return (int x) {};
+  });
+
+  Expect.type<Contra<Contra<int>>>(a.method6());
+  Contra<Contra<int>> method6Function = a.method6();
+  method6Function((int x) {});
+
+  Expect.type<Cov<Cov<int>>>(a.method7());
+  Cov<Cov<int>> method7Function = a.method7();
+  Expect.type<Cov<int>>(method7Function());
+  Cov<int> method7NestedFunction = method7Function();
+  Expect.isNull(method7NestedFunction());
+}
+
+void testMixin() {
+  B b = new B();
+
+  Expect.isNull(b.method1());
+
+  b.method2((int x) {
+    Expect.equals(2, x);
+  });
+
+  Expect.type<Cov<int>>(b.method3());
+  Cov<int> method3Function = b.method3();
+  Expect.isNull(method3Function());
+
+  b.method4((Cov<int> x) {});
+
+  b.method5(() {
+    return (int x) {};
+  });
+
+  Expect.type<Contra<Contra<int>>>(b.method6());
+  Contra<Contra<int>> method6Function = b.method6();
+  method6Function((int x) {});
+
+  Expect.type<Cov<Cov<int>>>(b.method7());
+  Cov<Cov<int>> method7Function = b.method7();
+  Expect.type<Cov<int>>(method7Function());
+  Cov<int> method7NestedFunction = method7Function();
+  Expect.isNull(method7NestedFunction());
+}
+
+void testClassInMethods() {
+  C<int> c = new C();
+
+  c.method1((A<int> x) {});
+
+  Expect.type<A<int>>(c.method2());
+}
+
+main() {
+  testClass();
+  testMixin();
+  testClassInMethods();
+}
diff --git a/tests/modular/issue38703/main.dart b/tests/modular/issue38703/main.dart
new file mode 100644
index 0000000..076b9f1
--- /dev/null
+++ b/tests/modular/issue38703/main.dart
@@ -0,0 +1,8 @@
+import 'others.dart';
+import 'package:expect/expect.dart';
+
+const Map<Key, String> m = {someKey: "PASSED"};
+
+main() {
+  Expect.equals(m[someKey], "PASSED");
+}
diff --git a/tests/modular/issue38703/modules.yaml b/tests/modular/issue38703/modules.yaml
new file mode 100644
index 0000000..1de7375
--- /dev/null
+++ b/tests/modular/issue38703/modules.yaml
@@ -0,0 +1,2 @@
+dependencies:
+  main: [others, expect]
diff --git a/tests/modular/issue38703/others.dart b/tests/modular/issue38703/others.dart
new file mode 100644
index 0000000..3a6a4e8
--- /dev/null
+++ b/tests/modular/issue38703/others.dart
@@ -0,0 +1,9 @@
+typedef FuncType<T> = Function();
+
+class Key<T> {
+  final FuncType<T> f;
+  const Key(this.f);
+}
+
+someFunc<T>() {}
+const someKey = Key(someFunc);
diff --git a/tools/VERSION b/tools/VERSION
index 72b118c..47453cd 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -33,7 +33,7 @@
 MAJOR 2
 MINOR 6
 PATCH 0
-PRERELEASE 5
+PRERELEASE 6
 PRERELEASE_PATCH 0
-ABI_VERSION 16
+ABI_VERSION 17
 OLDEST_SUPPORTED_ABI_VERSION 16
diff --git a/utils/dartdevc/BUILD.gn b/utils/dartdevc/BUILD.gn
index 2048ad4..ef1bc76 100644
--- a/utils/dartdevc/BUILD.gn
+++ b/utils/dartdevc/BUILD.gn
@@ -91,11 +91,6 @@
   }
 }
 
-dart2js_compile("dartdevc_web") {
-  main = rebase_path("../../pkg/dev_compiler/web/main.dart")
-  out = "$root_out_dir/dev_compiler/build/web/ddc_web_compiler.js"
-}
-
 dart2js_compile("stack_trace_mapper") {
   main = rebase_path("../../pkg/dev_compiler/web/stack_trace_mapper.dart")
   out = "$root_out_dir/dev_compiler/build/web/dart_stack_trace_mapper.js"
@@ -212,8 +207,13 @@
     ":dartdevc_kernel_sdk",
     ":dartdevc_sdk",
     ":dartdevc_test_pkg",
-    "../../sdk:create_sdk",
   ]
+
+  if (use_nnbd) {
+    deps += [ "../../sdk_nnbd:create_sdk" ]
+  } else {
+    deps += [ "../../sdk:create_sdk" ]
+  }
 }
 
 # Builds everything needed to run dartdevc tests locally using test.dart without