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..5b76473 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) {} }
+```
+